summaryrefslogtreecommitdiff
path: root/resources
diff options
context:
space:
mode:
Diffstat (limited to 'resources')
-rw-r--r--resources/Resources.php379
-rw-r--r--resources/assets/file-type-icons/COPYING2
-rw-r--r--resources/assets/poweredby_mediawiki_132x47.pngbin0 -> 6011 bytes
-rw-r--r--resources/assets/poweredby_mediawiki_176x62.pngbin0 -> 8796 bytes
-rw-r--r--resources/lib/jquery.client/AUTHORS.txt9
-rw-r--r--resources/lib/jquery.client/LICENSE-MIT.txt20
-rw-r--r--resources/lib/jquery.client/README.md6
-rw-r--r--resources/lib/jquery.client/jquery.client.js (renamed from resources/src/jquery/jquery.client.js)26
-rw-r--r--resources/lib/jquery.ui/themes/smoothness/PATCHES3
-rw-r--r--resources/lib/jquery.ui/themes/smoothness/jquery.ui.core.css2
-rw-r--r--resources/lib/jquery.ui/themes/smoothness/jquery.ui.theme.css4
-rw-r--r--resources/lib/jquery/jquery.jStorage.js20
-rw-r--r--resources/lib/jquery/jquery.js13
-rw-r--r--resources/lib/jquery/jquery.json.js199
-rw-r--r--resources/lib/jquery/jquery.migrate.js551
-rw-r--r--resources/lib/jquery/jquery.qunit.js2288
-rw-r--r--resources/lib/moment/locale/af.js4
-rw-r--r--resources/lib/moment/locale/ar-ma.js3
-rw-r--r--resources/lib/moment/locale/ar-sa.js5
-rw-r--r--resources/lib/moment/locale/ar.js5
-rw-r--r--resources/lib/moment/locale/az.js4
-rw-r--r--resources/lib/moment/locale/be.js4
-rw-r--r--resources/lib/moment/locale/bg.js4
-rw-r--r--resources/lib/moment/locale/bn.js3
-rw-r--r--resources/lib/moment/locale/bo.js3
-rw-r--r--resources/lib/moment/locale/br.js4
-rw-r--r--resources/lib/moment/locale/bs.js8
-rw-r--r--resources/lib/moment/locale/ca.js15
-rw-r--r--resources/lib/moment/locale/cs.js6
-rw-r--r--resources/lib/moment/locale/cv.js4
-rw-r--r--resources/lib/moment/locale/cy.js4
-rw-r--r--resources/lib/moment/locale/da.js4
-rw-r--r--resources/lib/moment/locale/de-at.js16
-rw-r--r--resources/lib/moment/locale/de.js16
-rw-r--r--resources/lib/moment/locale/el.js10
-rw-r--r--resources/lib/moment/locale/en-au.js4
-rw-r--r--resources/lib/moment/locale/en-ca.js4
-rw-r--r--resources/lib/moment/locale/en-gb.js4
-rw-r--r--resources/lib/moment/locale/eo.js4
-rw-r--r--resources/lib/moment/locale/es.js4
-rw-r--r--resources/lib/moment/locale/et.js4
-rw-r--r--resources/lib/moment/locale/eu.js4
-rw-r--r--resources/lib/moment/locale/fa.js4
-rw-r--r--resources/lib/moment/locale/fi.js4
-rw-r--r--resources/lib/moment/locale/fo.js4
-rw-r--r--resources/lib/moment/locale/fr-ca.js4
-rw-r--r--resources/lib/moment/locale/fr.js4
-rw-r--r--resources/lib/moment/locale/gl.js4
-rw-r--r--resources/lib/moment/locale/he.js3
-rw-r--r--resources/lib/moment/locale/hi.js3
-rw-r--r--resources/lib/moment/locale/hr.js4
-rw-r--r--resources/lib/moment/locale/hu.js4
-rw-r--r--resources/lib/moment/locale/hy-am.js4
-rw-r--r--resources/lib/moment/locale/id.js3
-rw-r--r--resources/lib/moment/locale/is.js4
-rw-r--r--resources/lib/moment/locale/it.js13
-rw-r--r--resources/lib/moment/locale/ja.js3
-rw-r--r--resources/lib/moment/locale/ka.js4
-rw-r--r--resources/lib/moment/locale/km.js3
-rw-r--r--resources/lib/moment/locale/ko.js4
-rw-r--r--resources/lib/moment/locale/lb.js4
-rw-r--r--resources/lib/moment/locale/lt.js4
-rw-r--r--resources/lib/moment/locale/lv.js4
-rw-r--r--resources/lib/moment/locale/mk.js4
-rw-r--r--resources/lib/moment/locale/ml.js3
-rw-r--r--resources/lib/moment/locale/mr.js3
-rw-r--r--resources/lib/moment/locale/ms-my.js3
-rw-r--r--resources/lib/moment/locale/my.js3
-rw-r--r--resources/lib/moment/locale/nb.js4
-rw-r--r--resources/lib/moment/locale/ne.js3
-rw-r--r--resources/lib/moment/locale/nl.js4
-rw-r--r--resources/lib/moment/locale/nn.js4
-rw-r--r--resources/lib/moment/locale/pl.js4
-rw-r--r--resources/lib/moment/locale/pt-br.js4
-rw-r--r--resources/lib/moment/locale/pt.js4
-rw-r--r--resources/lib/moment/locale/ro.js3
-rw-r--r--resources/lib/moment/locale/ru.js40
-rw-r--r--resources/lib/moment/locale/sk.js4
-rw-r--r--resources/lib/moment/locale/sl.js4
-rw-r--r--resources/lib/moment/locale/sq.js4
-rw-r--r--resources/lib/moment/locale/sr-cyrl.js4
-rw-r--r--resources/lib/moment/locale/sr.js4
-rw-r--r--resources/lib/moment/locale/sv.js4
-rw-r--r--resources/lib/moment/locale/ta.js4
-rw-r--r--resources/lib/moment/locale/th.js3
-rw-r--r--resources/lib/moment/locale/tl-ph.js4
-rw-r--r--resources/lib/moment/locale/tr.js4
-rw-r--r--resources/lib/moment/locale/tzm-latn.js3
-rw-r--r--resources/lib/moment/locale/tzm.js3
-rw-r--r--resources/lib/moment/locale/uk.js4
-rw-r--r--resources/lib/moment/locale/uz.js3
-rw-r--r--resources/lib/moment/locale/vi.js4
-rw-r--r--resources/lib/moment/locale/zh-cn.js4
-rw-r--r--resources/lib/moment/locale/zh-tw.js4
-rw-r--r--resources/lib/moment/moment.js148
-rw-r--r--resources/lib/mustache/mustache.js578
-rw-r--r--resources/lib/oojs-ui/i18n/ace.json1
-rw-r--r--resources/lib/oojs-ui/i18n/af.json13
-rw-r--r--resources/lib/oojs-ui/i18n/am.json3
-rw-r--r--resources/lib/oojs-ui/i18n/ar.json8
-rw-r--r--resources/lib/oojs-ui/i18n/arc.json3
-rw-r--r--resources/lib/oojs-ui/i18n/awa.json8
-rw-r--r--resources/lib/oojs-ui/i18n/az.json1
-rw-r--r--resources/lib/oojs-ui/i18n/ba.json1
-rw-r--r--resources/lib/oojs-ui/i18n/bcc.json9
-rw-r--r--resources/lib/oojs-ui/i18n/bcl.json1
-rw-r--r--resources/lib/oojs-ui/i18n/be-tarask.json1
-rw-r--r--resources/lib/oojs-ui/i18n/be.json7
-rw-r--r--resources/lib/oojs-ui/i18n/bg.json1
-rw-r--r--resources/lib/oojs-ui/i18n/bn.json16
-rw-r--r--resources/lib/oojs-ui/i18n/br.json8
-rw-r--r--resources/lib/oojs-ui/i18n/bs.json13
-rw-r--r--resources/lib/oojs-ui/i18n/ca.json16
-rw-r--r--resources/lib/oojs-ui/i18n/ce.json10
-rw-r--r--resources/lib/oojs-ui/i18n/ckb.json6
-rw-r--r--resources/lib/oojs-ui/i18n/co.json1
-rw-r--r--resources/lib/oojs-ui/i18n/crh-cyrl.json8
-rw-r--r--resources/lib/oojs-ui/i18n/crh-latn.json8
-rw-r--r--resources/lib/oojs-ui/i18n/cs.json8
-rw-r--r--resources/lib/oojs-ui/i18n/cu.json4
-rw-r--r--resources/lib/oojs-ui/i18n/cy.json1
-rw-r--r--resources/lib/oojs-ui/i18n/da.json1
-rw-r--r--resources/lib/oojs-ui/i18n/de.json5
-rw-r--r--resources/lib/oojs-ui/i18n/diq.json1
-rw-r--r--resources/lib/oojs-ui/i18n/dsb.json1
-rw-r--r--resources/lib/oojs-ui/i18n/egl.json7
-rw-r--r--resources/lib/oojs-ui/i18n/el.json5
-rw-r--r--resources/lib/oojs-ui/i18n/eml.json7
-rw-r--r--resources/lib/oojs-ui/i18n/en.json5
-rw-r--r--resources/lib/oojs-ui/i18n/eo.json1
-rw-r--r--resources/lib/oojs-ui/i18n/es.json5
-rw-r--r--resources/lib/oojs-ui/i18n/et.json5
-rw-r--r--resources/lib/oojs-ui/i18n/eu.json13
-rw-r--r--resources/lib/oojs-ui/i18n/fa.json8
-rw-r--r--resources/lib/oojs-ui/i18n/fi.json5
-rw-r--r--resources/lib/oojs-ui/i18n/fo.json12
-rw-r--r--resources/lib/oojs-ui/i18n/fr.json8
-rw-r--r--resources/lib/oojs-ui/i18n/frr.json1
-rw-r--r--resources/lib/oojs-ui/i18n/fur.json1
-rw-r--r--resources/lib/oojs-ui/i18n/fy.json11
-rw-r--r--resources/lib/oojs-ui/i18n/gl.json8
-rw-r--r--resources/lib/oojs-ui/i18n/he.json5
-rw-r--r--resources/lib/oojs-ui/i18n/hi.json14
-rw-r--r--resources/lib/oojs-ui/i18n/hr.json2
-rw-r--r--resources/lib/oojs-ui/i18n/hsb.json11
-rw-r--r--resources/lib/oojs-ui/i18n/hu.json5
-rw-r--r--resources/lib/oojs-ui/i18n/hy.json5
-rw-r--r--resources/lib/oojs-ui/i18n/id.json12
-rw-r--r--resources/lib/oojs-ui/i18n/ie.json1
-rw-r--r--resources/lib/oojs-ui/i18n/ilo.json5
-rw-r--r--resources/lib/oojs-ui/i18n/is.json12
-rw-r--r--resources/lib/oojs-ui/i18n/it.json5
-rw-r--r--resources/lib/oojs-ui/i18n/ja.json8
-rw-r--r--resources/lib/oojs-ui/i18n/jv.json1
-rw-r--r--resources/lib/oojs-ui/i18n/ka.json12
-rw-r--r--resources/lib/oojs-ui/i18n/kk-cyrl.json11
-rw-r--r--resources/lib/oojs-ui/i18n/km.json1
-rw-r--r--resources/lib/oojs-ui/i18n/kn.json21
-rw-r--r--resources/lib/oojs-ui/i18n/ko.json5
-rw-r--r--resources/lib/oojs-ui/i18n/krc.json11
-rw-r--r--resources/lib/oojs-ui/i18n/ksh.json19
-rw-r--r--resources/lib/oojs-ui/i18n/ku-latn.json13
-rw-r--r--resources/lib/oojs-ui/i18n/kw.json3
-rw-r--r--resources/lib/oojs-ui/i18n/ky.json3
-rw-r--r--resources/lib/oojs-ui/i18n/lb.json5
-rw-r--r--resources/lib/oojs-ui/i18n/lmo.json1
-rw-r--r--resources/lib/oojs-ui/i18n/lt.json1
-rw-r--r--resources/lib/oojs-ui/i18n/lv.json6
-rw-r--r--resources/lib/oojs-ui/i18n/lzh.json2
-rw-r--r--resources/lib/oojs-ui/i18n/mg.json3
-rw-r--r--resources/lib/oojs-ui/i18n/min.json7
-rw-r--r--resources/lib/oojs-ui/i18n/mk.json5
-rw-r--r--resources/lib/oojs-ui/i18n/ml.json1
-rw-r--r--resources/lib/oojs-ui/i18n/mr.json1
-rw-r--r--resources/lib/oojs-ui/i18n/nap.json1
-rw-r--r--resources/lib/oojs-ui/i18n/nb.json8
-rw-r--r--resources/lib/oojs-ui/i18n/nds-nl.json13
-rw-r--r--resources/lib/oojs-ui/i18n/nds.json1
-rw-r--r--resources/lib/oojs-ui/i18n/ne.json12
-rw-r--r--resources/lib/oojs-ui/i18n/nl.json5
-rw-r--r--resources/lib/oojs-ui/i18n/nn.json1
-rw-r--r--resources/lib/oojs-ui/i18n/oc.json5
-rw-r--r--resources/lib/oojs-ui/i18n/om.json5
-rw-r--r--resources/lib/oojs-ui/i18n/or.json13
-rw-r--r--resources/lib/oojs-ui/i18n/pa.json15
-rw-r--r--resources/lib/oojs-ui/i18n/pfl.json6
-rw-r--r--resources/lib/oojs-ui/i18n/pl.json5
-rw-r--r--resources/lib/oojs-ui/i18n/pms.json1
-rw-r--r--resources/lib/oojs-ui/i18n/ps.json11
-rw-r--r--resources/lib/oojs-ui/i18n/pt-br.json1
-rw-r--r--resources/lib/oojs-ui/i18n/pt.json5
-rw-r--r--resources/lib/oojs-ui/i18n/qqq.json5
-rw-r--r--resources/lib/oojs-ui/i18n/qu.json1
-rw-r--r--resources/lib/oojs-ui/i18n/ro.json5
-rw-r--r--resources/lib/oojs-ui/i18n/roa-tara.json12
-rw-r--r--resources/lib/oojs-ui/i18n/ru.json8
-rw-r--r--resources/lib/oojs-ui/i18n/sah.json3
-rw-r--r--resources/lib/oojs-ui/i18n/scn.json4
-rw-r--r--resources/lib/oojs-ui/i18n/sco.json1
-rw-r--r--resources/lib/oojs-ui/i18n/sh.json1
-rw-r--r--resources/lib/oojs-ui/i18n/si.json1
-rw-r--r--resources/lib/oojs-ui/i18n/sk.json2
-rw-r--r--resources/lib/oojs-ui/i18n/sl.json5
-rw-r--r--resources/lib/oojs-ui/i18n/sr-ec.json5
-rw-r--r--resources/lib/oojs-ui/i18n/sr-el.json10
-rw-r--r--resources/lib/oojs-ui/i18n/sv.json5
-rw-r--r--resources/lib/oojs-ui/i18n/ta.json6
-rw-r--r--resources/lib/oojs-ui/i18n/te.json3
-rw-r--r--resources/lib/oojs-ui/i18n/tg-cyrl.json1
-rw-r--r--resources/lib/oojs-ui/i18n/th.json1
-rw-r--r--resources/lib/oojs-ui/i18n/tl.json7
-rw-r--r--resources/lib/oojs-ui/i18n/tr.json15
-rw-r--r--resources/lib/oojs-ui/i18n/tt-cyrl.json1
-rw-r--r--resources/lib/oojs-ui/i18n/uk.json8
-rw-r--r--resources/lib/oojs-ui/i18n/uz.json1
-rw-r--r--resources/lib/oojs-ui/i18n/vec.json4
-rw-r--r--resources/lib/oojs-ui/i18n/vi.json8
-rw-r--r--resources/lib/oojs-ui/i18n/vo.json1
-rw-r--r--resources/lib/oojs-ui/i18n/yo.json1
-rw-r--r--resources/lib/oojs-ui/i18n/zh-hans.json11
-rw-r--r--resources/lib/oojs-ui/i18n/zh-hant.json10
-rw-r--r--resources/lib/oojs-ui/images/anchor.pngbin203 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/anchor.svg7
-rw-r--r--resources/lib/oojs-ui/images/grab.curbin0 -> 326 bytes
-rw-r--r--resources/lib/oojs-ui/images/grabbing.curbin0 -> 326 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/accept.pngbin332 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/accept.svg6
-rw-r--r--resources/lib/oojs-ui/images/icons/add-item.pngbin145 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/advanced.pngbin531 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/advanced.svg6
-rw-r--r--resources/lib/oojs-ui/images/icons/alert.pngbin448 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/arched-arrow-ltr.pngbin294 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/arched-arrow-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/images/icons/arched-arrow-rtl.pngbin296 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/arched-arrow-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/images/icons/check.pngbin235 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/check.svg6
-rw-r--r--resources/lib/oojs-ui/images/icons/clear.pngbin430 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/close.pngbin286 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/close.svg6
-rw-r--r--resources/lib/oojs-ui/images/icons/code.pngbin313 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/collapse.pngbin221 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/comment.pngbin244 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/expand.pngbin237 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/help.pngbin591 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/history.pngbin591 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/info.pngbin349 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/link.pngbin348 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/link.svg8
-rw-r--r--resources/lib/oojs-ui/images/icons/menu.pngbin190 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/menu.svg6
-rw-r--r--resources/lib/oojs-ui/images/icons/move-ltr.pngbin254 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/move-rtl.pngbin250 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/picture.pngbin402 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/remove-item.svg6
-rw-r--r--resources/lib/oojs-ui/images/icons/remove.pngbin175 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/search.pngbin267 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/search.svg6
-rw-r--r--resources/lib/oojs-ui/images/icons/settings.pngbin230 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/tag.pngbin319 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/icons/window.pngbin309 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/indicators/alert.pngbin256 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/indicators/arrow-down.pngbin199 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/indicators/arrow-down.svg6
-rw-r--r--resources/lib/oojs-ui/images/indicators/arrow-ltr.pngbin204 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/indicators/arrow-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/images/indicators/arrow-rtl.pngbin194 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/indicators/arrow-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/images/indicators/arrow-up.pngbin180 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/indicators/arrow-up.svg6
-rw-r--r--resources/lib/oojs-ui/images/indicators/required.pngbin264 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/images/toolbar-shadow.pngbin131 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/oojs-ui-apex.css1945
-rw-r--r--resources/lib/oojs-ui/oojs-ui-apex.rtl.css1929
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-alerts.css64
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-content.css76
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-advanced.css166
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-core.css88
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-list.css34
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-styling.css495
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-interactions.css106
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-layout.css100
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-location.css34
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-media.css46
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-moderation.css148
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-movement.css64
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-user.css34
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-icons-wikimedia.css28
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki-noimages.css2660
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki.css3204
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki.js66
-rw-r--r--resources/lib/oojs-ui/oojs-ui-minerva.css1397
-rw-r--r--resources/lib/oojs-ui/oojs-ui-minerva.rtl.css1381
-rw-r--r--resources/lib/oojs-ui/oojs-ui.css1159
-rw-r--r--resources/lib/oojs-ui/oojs-ui.js10609
-rw-r--r--resources/lib/oojs-ui/oojs-ui.rtl.css112
-rw-r--r--resources/lib/oojs-ui/oojs-ui.svg.css112
-rw-r--r--resources/lib/oojs-ui/oojs-ui.svg.rtl.css112
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.pngbin0 -> 152 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.pngbin0 -> 148 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/add.pngbin0 -> 144 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/add.svg (renamed from resources/lib/oojs-ui/images/icons/add-item.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.pngbin0 -> 453 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.pngbin0 -> 404 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.pngbin0 -> 469 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.pngbin0 -> 594 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.pngbin0 -> 433 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.svg (renamed from resources/lib/oojs-ui/images/icons/alert.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.pngbin0 -> 165 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left.pngbin0 -> 176 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right.pngbin0 -> 176 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr-invert.pngbin0 -> 351 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr.pngbin0 -> 309 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl-invert.pngbin0 -> 331 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl.pngbin0 -> 286 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr.pngbin0 -> 197 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl.pngbin0 -> 198 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr.pngbin0 -> 197 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl.pngbin0 -> 190 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.pngbin0 -> 304 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.pngbin0 -> 295 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr.pngbin0 -> 345 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl.pngbin0 -> 377 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.pngbin0 -> 256 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.pngbin0 -> 365 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.pngbin0 -> 376 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/beta.pngbin0 -> 348 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/beta.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.pngbin0 -> 304 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.pngbin0 -> 341 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.pngbin0 -> 342 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.pngbin0 -> 461 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.pngbin0 -> 323 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/block.pngbin0 -> 295 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/block.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr-invert.pngbin0 -> 329 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr.pngbin0 -> 309 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl-invert.pngbin0 -> 342 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl.pngbin0 -> 317 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.pngbin0 -> 276 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain.pngbin0 -> 289 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.pngbin0 -> 315 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to.pngbin0 -> 342 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.pngbin0 -> 219 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be.pngbin0 -> 232 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te.pngbin0 -> 145 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe.pngbin0 -> 343 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.pngbin0 -> 150 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.pngbin0 -> 315 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man.pngbin0 -> 297 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.pngbin0 -> 143 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.pngbin0 -> 176 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.pngbin0 -> 256 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.pngbin0 -> 238 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.pngbin0 -> 236 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.pngbin0 -> 221 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.pngbin0 -> 216 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.pngbin0 -> 208 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.pngbin0 -> 201 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.pngbin0 -> 378 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.pngbin0 -> 351 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.svg (renamed from resources/lib/oojs-ui/images/icons/clear.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.pngbin0 -> 250 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.pngbin0 -> 252 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.pngbin0 -> 246 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.pngbin0 -> 252 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.pngbin0 -> 368 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/check-constructive.pngbin0 -> 252 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/check-constructive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/check-invert.pngbin0 -> 190 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/check-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/check-progressive.pngbin0 -> 280 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/check-progressive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/check.pngbin0 -> 183 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/check.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.pngbin0 -> 337 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.pngbin0 -> 274 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.pngbin0 -> 244 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr.pngbin0 -> 224 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl.pngbin0 -> 225 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.pngbin0 -> 316 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.pngbin0 -> 334 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr-invert.pngbin0 -> 333 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.pngbin0 -> 296 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl-invert.pngbin0 -> 357 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.pngbin0 -> 319 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.pngbin0 -> 297 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/code.pngbin0 -> 272 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/code.svg (renamed from resources/lib/oojs-ui/images/icons/code.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.pngbin0 -> 204 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.pngbin0 -> 207 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.svg (renamed from resources/lib/oojs-ui/images/icons/collapse.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.pngbin0 -> 233 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/comment.pngbin0 -> 211 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/comment.svg (renamed from resources/lib/oojs-ui/images/icons/comment.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.pngbin0 -> 220 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.pngbin0 -> 223 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.pngbin0 -> 212 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr.pngbin0 -> 252 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl.pngbin0 -> 262 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-invert.pngbin0 -> 320 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-progressive.pngbin0 -> 477 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-progressive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr.pngbin0 -> 282 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-invert.pngbin0 -> 314 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-progressive.pngbin0 -> 480 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-progressive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.pngbin0 -> 284 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr-invert.pngbin0 -> 360 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.pngbin0 -> 312 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl-invert.pngbin0 -> 369 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.pngbin0 -> 328 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr-invert.pngbin0 -> 447 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr-invert.svg11
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.pngbin0 -> 390 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.svg11
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl-invert.pngbin0 -> 439 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl-invert.svg11
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.pngbin0 -> 379 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.svg11
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis-invert.pngbin0 -> 172 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis-invert.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis.pngbin0 -> 166 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.pngbin0 -> 212 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/expand.pngbin0 -> 196 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/expand.svg (renamed from resources/lib/oojs-ui/images/icons/expand.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr-invert.pngbin0 -> 184 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr.pngbin0 -> 168 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl-invert.pngbin0 -> 180 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl.pngbin0 -> 164 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.pngbin0 -> 353 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.pngbin0 -> 324 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.pngbin0 -> 298 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.pngbin0 -> 297 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr-invert.pngbin0 -> 260 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.pngbin0 -> 231 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl-invert.pngbin0 -> 263 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.pngbin0 -> 237 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr-invert.pngbin0 -> 306 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr-invert.svg16
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.pngbin0 -> 295 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.svg16
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl-invert.pngbin0 -> 309 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl-invert.svg16
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.pngbin0 -> 294 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.svg16
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.pngbin0 -> 163 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.pngbin0 -> 167 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.pngbin0 -> 231 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl.pngbin0 -> 233 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/heart.pngbin0 -> 263 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/heart.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr-invert.pngbin0 -> 603 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr-invert.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.pngbin0 -> 529 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.svg (renamed from resources/lib/oojs-ui/images/icons/help.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl-invert.pngbin0 -> 622 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl-invert.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.pngbin0 -> 543 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.pngbin0 -> 628 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/history.pngbin0 -> 543 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/history.svg (renamed from resources/lib/oojs-ui/images/icons/history.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr.pngbin0 -> 212 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl.pngbin0 -> 207 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.pngbin0 -> 253 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.pngbin0 -> 237 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.pngbin0 -> 281 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.pngbin0 -> 288 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr.pngbin0 -> 194 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl.pngbin0 -> 187 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.pngbin0 -> 377 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/info.pngbin0 -> 328 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/info.svg (renamed from resources/lib/oojs-ui/images/icons/info.svg)6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.pngbin0 -> 144 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.pngbin0 -> 284 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem.pngbin0 -> 333 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem.pngbin0 -> 271 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha.pngbin0 -> 339 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.pngbin0 -> 300 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.pngbin0 -> 324 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.pngbin0 -> 254 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan.pngbin0 -> 287 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.pngbin0 -> 208 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.pngbin0 -> 285 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.pngbin0 -> 321 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.pngbin0 -> 184 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.pngbin0 -> 193 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.pngbin0 -> 286 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.pngbin0 -> 280 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr.pngbin0 -> 185 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl.pngbin0 -> 187 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/language.pngbin0 -> 410 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/language.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.pngbin0 -> 166 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.pngbin0 -> 163 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr-invert.pngbin0 -> 467 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr-invert.svg13
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.pngbin0 -> 423 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.svg13
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl-invert.pngbin0 -> 506 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl.pngbin0 -> 444 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.pngbin0 -> 193 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.pngbin0 -> 178 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.pngbin0 -> 174 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.pngbin0 -> 184 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-destructive.pngbin0 -> 347 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-destructive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-invert.pngbin0 -> 262 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr.pngbin0 -> 239 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-destructive.pngbin0 -> 344 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-destructive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-invert.pngbin0 -> 257 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl.pngbin0 -> 241 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr.pngbin0 -> 219 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl.pngbin0 -> 225 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc.pngbin0 -> 373 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.pngbin0 -> 521 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.pngbin0 -> 459 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.pngbin0 -> 265 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.pngbin0 -> 303 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.pngbin0 -> 367 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.pngbin0 -> 384 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.pngbin0 -> 378 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.pngbin0 -> 181 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.pngbin0 -> 170 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.pngbin0 -> 290 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl.pngbin0 -> 300 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr-invert.pngbin0 -> 225 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr.pngbin0 -> 219 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr.svg (renamed from resources/lib/oojs-ui/images/icons/move-ltr.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl-invert.pngbin0 -> 221 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.pngbin0 -> 214 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.svg (renamed from resources/lib/oojs-ui/images/icons/move-rtl.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move.pngbin0 -> 249 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.pngbin0 -> 216 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl.pngbin0 -> 222 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.pngbin0 -> 267 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl.pngbin0 -> 282 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.pngbin0 -> 188 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.pngbin0 -> 189 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr.pngbin0 -> 234 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl.pngbin0 -> 228 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr.pngbin0 -> 190 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl.pngbin0 -> 193 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.pngbin0 -> 153 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.pngbin0 -> 154 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr.pngbin0 -> 220 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl.pngbin0 -> 213 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.pngbin0 -> 396 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.pngbin0 -> 350 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.svg (renamed from resources/lib/oojs-ui/images/icons/picture.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr.pngbin0 -> 307 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl.pngbin0 -> 302 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.pngbin0 -> 222 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.pngbin0 -> 221 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.pngbin0 -> 344 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.pngbin0 -> 360 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.pngbin0 -> 319 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.svg11
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.pngbin0 -> 326 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.svg11
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.pngbin0 -> 293 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.pngbin0 -> 287 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.pngbin0 -> 382 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.pngbin0 -> 381 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.pngbin0 -> 340 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.pngbin0 -> 189 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.pngbin0 -> 181 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/remove.pngbin0 -> 172 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/remove.svg (renamed from resources/lib/oojs-ui/images/icons/remove.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.pngbin0 -> 402 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr-invert.pngbin0 -> 372 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.pngbin0 -> 350 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl-invert.pngbin0 -> 376 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.pngbin0 -> 341 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link-invert.pngbin0 -> 215 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.pngbin0 -> 201 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.pngbin0 -> 202 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/settings.pngbin0 -> 191 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/settings.svg (renamed from resources/lib/oojs-ui/images/icons/settings.svg)6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.pngbin0 -> 432 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.pngbin0 -> 446 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.pngbin0 -> 341 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.pngbin0 -> 342 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.pngbin0 -> 360 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr.pngbin0 -> 158 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl.pngbin0 -> 180 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.pngbin0 -> 189 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.pngbin0 -> 214 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr.pngbin0 -> 179 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl.pngbin0 -> 184 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.pngbin0 -> 484 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/star.pngbin0 -> 435 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/star.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.pngbin0 -> 368 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.pngbin0 -> 299 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.pngbin0 -> 306 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.pngbin0 -> 244 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr-invert.pngbin0 -> 159 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.pngbin0 -> 152 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl-invert.pngbin0 -> 164 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.pngbin0 -> 156 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.pngbin0 -> 142 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.svg12
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.png (renamed from resources/lib/oojs-ui/images/icons/remove-item.png)bin131 -> 134 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.svg12
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr-invert.pngbin0 -> 148 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr.pngbin0 -> 140 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl-invert.pngbin0 -> 147 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl.pngbin0 -> 140 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-invert.pngbin0 -> 159 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-progressive.pngbin0 -> 160 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-progressive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr.pngbin0 -> 153 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-invert.pngbin0 -> 159 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-progressive.pngbin0 -> 160 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-progressive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl.pngbin0 -> 151 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.pngbin0 -> 244 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.pngbin0 -> 240 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.pngbin0 -> 409 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.pngbin0 -> 392 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.pngbin0 -> 241 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.pngbin0 -> 240 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.pngbin0 -> 154 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr.pngbin0 -> 164 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr.svg11
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl.pngbin0 -> 165 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl.svg11
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after.pngbin0 -> 153 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after.svg11
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before.pngbin0 -> 151 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before.svg11
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells.pngbin0 -> 220 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table.pngbin0 -> 150 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.pngbin0 -> 419 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.pngbin0 -> 438 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.pngbin0 -> 295 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.pngbin0 -> 424 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.pngbin0 -> 403 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.pngbin0 -> 262 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.svg (renamed from resources/lib/oojs-ui/images/icons/tag.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.pngbin0 -> 193 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.pngbin0 -> 202 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright.pngbin0 -> 224 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft.pngbin0 -> 233 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.pngbin0 -> 306 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.pngbin0 -> 429 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.pngbin0 -> 437 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.pngbin0 -> 204 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.pngbin0 -> 193 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr-invert.pngbin0 -> 282 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr.pngbin0 -> 254 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl-invert.pngbin0 -> 298 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.pngbin0 -> 280 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-destructive.pngbin0 -> 348 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-destructive.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-invert.pngbin0 -> 265 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.pngbin0 -> 245 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-destructive.pngbin0 -> 345 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-destructive.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-invert.pngbin0 -> 265 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.pngbin0 -> 245 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-invert.pngbin0 -> 298 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar.pngbin0 -> 262 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.pngbin0 -> 295 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.pngbin0 -> 220 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.pngbin0 -> 203 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr.pngbin0 -> 250 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl.pngbin0 -> 251 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.pngbin0 -> 323 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.pngbin0 -> 313 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.pngbin0 -> 265 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.pngbin0 -> 288 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.pngbin0 -> 277 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.pngbin0 -> 314 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.pngbin0 -> 333 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact-invert.pngbin0 -> 211 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact-invert.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact.pngbin0 -> 202 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr-invert.pngbin0 -> 245 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr-invert.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.pngbin0 -> 225 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl-invert.pngbin0 -> 215 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl-invert.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl.pngbin0 -> 201 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.pngbin0 -> 238 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator.pngbin0 -> 228 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr.pngbin0 -> 296 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.pngbin0 -> 285 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.pngbin0 -> 163 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.svg15
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.pngbin0 -> 409 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl.pngbin0 -> 405 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.pngbin0 -> 273 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/window.pngbin0 -> 251 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/window.svg (renamed from resources/lib/oojs-ui/images/icons/window.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.pngbin0 -> 264 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert.pngbin0 -> 233 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert.svg (renamed from resources/lib/oojs-ui/images/indicators/alert.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down-invert.pngbin0 -> 184 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.pngbin0 -> 173 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr-invert.pngbin0 -> 150 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.pngbin0 -> 143 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl-invert.pngbin0 -> 148 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.pngbin0 -> 142 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up-invert.pngbin0 -> 137 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.pngbin0 -> 132 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.pngbin0 -> 266 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/required.pngbin0 -> 241 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/required.svg (renamed from resources/lib/oojs-ui/images/indicators/required.svg)2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr-invert.pngbin0 -> 251 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.pngbin0 -> 231 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl-invert.pngbin0 -> 261 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.pngbin0 -> 234 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/textures/pending.gif (renamed from resources/lib/oojs-ui/images/textures/pending.gif)bin2032 -> 2032 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.png (renamed from resources/lib/oojs-ui/images/textures/transparency.png)bin145 -> 145 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.svg (renamed from resources/lib/oojs-ui/images/textures/transparency.svg)0
-rw-r--r--resources/lib/oojs-ui/themes/minerva/images/icons/check.pngbin640 -> 0 bytes
-rw-r--r--resources/lib/oojs-ui/themes/minerva/images/icons/check.svg8
-rw-r--r--resources/lib/oojs/oojs.jquery.js126
-rw-r--r--resources/lib/qunitjs/qunit.css (renamed from resources/lib/jquery/jquery.qunit.css)59
-rw-r--r--resources/lib/qunitjs/qunit.js2875
-rw-r--r--resources/src/jquery.json-deprecate.js8
-rw-r--r--resources/src/jquery.tipsy/jquery.tipsy.js23
-rw-r--r--resources/src/jquery/jquery.accessKeyLabel.js2
-rw-r--r--resources/src/jquery/jquery.arrowSteps.js2
-rw-r--r--resources/src/jquery/jquery.badge.css2
-rw-r--r--resources/src/jquery/jquery.badge.js3
-rw-r--r--resources/src/jquery/jquery.confirmable.js14
-rw-r--r--resources/src/jquery/jquery.confirmable.mediawiki.js4
-rw-r--r--resources/src/jquery/jquery.expandableField.js2
-rw-r--r--resources/src/jquery/jquery.footHovzer.js16
-rw-r--r--resources/src/jquery/jquery.getAttrs.js49
-rw-r--r--resources/src/jquery/jquery.hidpi.js4
-rw-r--r--resources/src/jquery/jquery.makeCollapsible.css24
-rw-r--r--resources/src/jquery/jquery.makeCollapsible.js4
-rw-r--r--resources/src/jquery/jquery.mwExtension.js8
-rw-r--r--resources/src/jquery/jquery.placeholder.js10
-rw-r--r--resources/src/jquery/jquery.qunit.completenessTest.js14
-rw-r--r--resources/src/jquery/jquery.suggestions.js149
-rw-r--r--resources/src/jquery/jquery.tabIndex.js8
-rw-r--r--resources/src/jquery/jquery.tablesorter.js167
-rw-r--r--resources/src/jquery/jquery.textSelection.js39
-rw-r--r--resources/src/mediawiki.action/images/nextredirect-ltr.pngbin121 -> 122 bytes
-rw-r--r--resources/src/mediawiki.action/images/nextredirect-ltr.svg9
-rw-r--r--resources/src/mediawiki.action/images/nextredirect-rtl.pngbin121 -> 118 bytes
-rw-r--r--resources/src/mediawiki.action/images/nextredirect-rtl.svg9
-rw-r--r--resources/src/mediawiki.action/images/redirect-ltr.pngbin128 -> 169 bytes
-rw-r--r--resources/src/mediawiki.action/images/redirect-ltr.svg9
-rw-r--r--resources/src/mediawiki.action/images/redirect-rtl.pngbin132 -> 139 bytes
-rw-r--r--resources/src/mediawiki.action/images/redirect-rtl.svg9
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js61
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.js232
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.preview.js257
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.stash.js76
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.styles.css8
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.history.diff.css7
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.history.diff.print.css16
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.history.js3
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.view.categoryPage.less11
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.view.dblClickEdit.js13
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.view.metadata.css10
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.view.postEdit.js11
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.view.redirect.js3
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.view.redirectPage.css20
-rw-r--r--resources/src/mediawiki.action/templates/postEdit.html6
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.category.js44
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.edit.js43
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.js87
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.login.js45
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.options.js89
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.parse.js12
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.watch.js21
-rw-r--r--resources/src/mediawiki.language/languages/fi.js2
-rw-r--r--resources/src/mediawiki.language/languages/hsb.js2
-rw-r--r--resources/src/mediawiki.language/languages/hy.js2
-rw-r--r--resources/src/mediawiki.language/languages/os.js18
-rw-r--r--resources/src/mediawiki.language/mediawiki.language.init.js2
-rw-r--r--resources/src/mediawiki.language/mediawiki.language.js41
-rw-r--r--resources/src/mediawiki.language/mediawiki.language.numbers.js6
-rw-r--r--resources/src/mediawiki.language/specialcharacters.json1
-rw-r--r--resources/src/mediawiki.legacy/ajax.js304
-rw-r--r--resources/src/mediawiki.legacy/commonPrint.css42
-rw-r--r--resources/src/mediawiki.legacy/images/magnify-clip-ltr.pngbin0 -> 336 bytes
-rw-r--r--resources/src/mediawiki.legacy/images/magnify-clip-ltr.svg7
-rw-r--r--resources/src/mediawiki.legacy/images/magnify-clip-rtl.pngbin0 -> 360 bytes
-rw-r--r--resources/src/mediawiki.legacy/images/magnify-clip-rtl.svg7
-rw-r--r--resources/src/mediawiki.legacy/oldshared.css6
-rw-r--r--resources/src/mediawiki.legacy/protect.js5
-rw-r--r--resources/src/mediawiki.legacy/shared.css28
-rw-r--r--resources/src/mediawiki.legacy/wikibits.js388
-rw-r--r--resources/src/mediawiki.less/mediawiki.mixins.less73
-rw-r--r--resources/src/mediawiki.less/mediawiki.ui/mixins.less29
-rw-r--r--resources/src/mediawiki.libs/CLDRPluralRuleParser.js246
-rw-r--r--resources/src/mediawiki.messagePoster/mediawiki.messagePoster.MessagePoster.js38
-rw-r--r--resources/src/mediawiki.messagePoster/mediawiki.messagePoster.WikitextMessagePoster.js53
-rw-r--r--resources/src/mediawiki.messagePoster/mediawiki.messagePoster.factory.js109
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.gallery.js425
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.image.pagination.js77
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.ready.js2
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.startup.js2
-rw-r--r--resources/src/mediawiki.skinning/content.css29
-rw-r--r--resources/src/mediawiki.skinning/elements.css13
-rw-r--r--resources/src/mediawiki.skinning/images/magnify-clip-ltr.pngbin204 -> 336 bytes
-rw-r--r--resources/src/mediawiki.skinning/images/magnify-clip-ltr.svg7
-rw-r--r--resources/src/mediawiki.skinning/images/magnify-clip-rtl.pngbin149 -> 360 bytes
-rw-r--r--resources/src/mediawiki.skinning/images/magnify-clip-rtl.svg7
-rw-r--r--resources/src/mediawiki.skinning/interface.css8
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.block.js2
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.changeslist.css8
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.changeslist.legend.css6
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.css5
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.edittags.css15
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.edittags.js24
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.import.js6
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.pageLanguage.js2
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.preferences.js66
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.search.css17
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.upload.js93
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.userlogin.common.css2
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.userlogin.common.js2
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.userlogin.login.css13
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.userlogin.signup.js2
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.version.css4
-rw-r--r--resources/src/mediawiki.special/templates/thumbnail.html9
-rw-r--r--resources/src/mediawiki.toolbar/images/ar/button_bold.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_bold.png)bin533 -> 533 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/ar/button_headline.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_headline.png)bin484 -> 484 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/ar/button_italic.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_italic.png)bin532 -> 532 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/ar/button_link.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_link.png)bin557 -> 557 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/ar/button_nowiki.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_nowiki.png)bin874 -> 874 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/be-tarask/button_bold.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/be-tarask/button_bold.png)bin550 -> 550 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/be-tarask/button_italic.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/be-tarask/button_italic.png)bin539 -> 539 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/be-tarask/button_link.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/be-tarask/button_link.png)bin419 -> 419 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/de/button_bold.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/de/button_bold.png)bin255 -> 255 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/de/button_italic.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/de/button_italic.png)bin260 -> 260 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/en/button_bold.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_bold.png)bin250 -> 250 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/en/button_extlink.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_extlink.png)bin435 -> 435 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/en/button_headline.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_headline.png)bin440 -> 440 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/en/button_hr.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_hr.png)bin200 -> 200 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/en/button_image.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_image.png)bin483 -> 483 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/en/button_italic.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_italic.png)bin250 -> 250 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/en/button_link.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_link.png)bin280 -> 280 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/en/button_media.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_media.png)bin728 -> 728 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/en/button_nowiki.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_nowiki.png)bin322 -> 322 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/en/button_sig.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_sig.png)bin920 -> 920 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/fa/button_bold.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_bold.png)bin459 -> 459 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/fa/button_headline.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_headline.png)bin392 -> 392 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/fa/button_italic.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_italic.png)bin512 -> 512 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/fa/button_link.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_link.png)bin485 -> 485 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/fa/button_nowiki.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_nowiki.png)bin874 -> 874 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/ksh/LICENSE (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ksh/LICENSE)0
-rw-r--r--resources/src/mediawiki.toolbar/images/ksh/button_italic.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ksh/button_italic.png)bin368 -> 368 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/ru/LICENSE (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/LICENSE)0
-rw-r--r--resources/src/mediawiki.toolbar/images/ru/button_bold.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/button_bold.png)bin254 -> 254 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/ru/button_italic.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/button_italic.png)bin423 -> 423 bytes
-rw-r--r--resources/src/mediawiki.toolbar/images/ru/button_link.png (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/button_link.png)bin278 -> 278 bytes
-rw-r--r--resources/src/mediawiki.toolbar/toolbar.js202
-rw-r--r--resources/src/mediawiki.toolbar/toolbar.less (renamed from resources/src/mediawiki.action/mediawiki.action.edit.toolbar/mediawiki.action.edit.toolbar.less)0
-rw-r--r--resources/src/mediawiki.ui/components/anchors.less89
-rw-r--r--resources/src/mediawiki.ui/components/buttons.less11
-rw-r--r--resources/src/mediawiki.ui/components/checkbox.less120
-rw-r--r--resources/src/mediawiki.ui/components/forms.less15
-rw-r--r--resources/src/mediawiki.ui/components/icons.less107
-rw-r--r--resources/src/mediawiki.ui/components/images/checked.svg2
-rw-r--r--resources/src/mediawiki.ui/components/images/checked_disabled.pngbin0 -> 333 bytes
-rw-r--r--resources/src/mediawiki.ui/components/images/checked_disabled.svg1
-rw-r--r--resources/src/mediawiki.ui/components/images/ok.pngbin0 -> 442 bytes
-rw-r--r--resources/src/mediawiki.ui/components/images/ok.svg1
-rw-r--r--resources/src/mediawiki.ui/components/images/radio_checked.pngbin0 -> 286 bytes
-rw-r--r--resources/src/mediawiki.ui/components/images/radio_checked.svg1
-rw-r--r--resources/src/mediawiki.ui/components/images/radio_disabled.pngbin0 -> 251 bytes
-rw-r--r--resources/src/mediawiki.ui/components/images/radio_disabled.svg1
-rw-r--r--resources/src/mediawiki.ui/components/inputs.less20
-rw-r--r--resources/src/mediawiki.ui/components/radio.less116
-rw-r--r--resources/src/mediawiki.ui/components/text.less40
-rw-r--r--resources/src/mediawiki/images/help.pngbin0 -> 460 bytes
-rw-r--r--resources/src/mediawiki/images/help.svg1
-rw-r--r--resources/src/mediawiki/images/pager-arrow-disabled-fastforward-ltr.svg44
-rw-r--r--resources/src/mediawiki/images/pager-arrow-disabled-fastforward-rtl.svg44
-rw-r--r--resources/src/mediawiki/images/pager-arrow-disabled-forward-ltr.svg36
-rw-r--r--resources/src/mediawiki/images/pager-arrow-disabled-forward-rtl.svg36
-rw-r--r--resources/src/mediawiki/images/pager-arrow-fastforward-ltr.svg43
-rw-r--r--resources/src/mediawiki/images/pager-arrow-fastforward-rtl.svg69
-rw-r--r--resources/src/mediawiki/images/pager-arrow-forward-ltr.svg36
-rw-r--r--resources/src/mediawiki/images/pager-arrow-forward-rtl.svg36
-rw-r--r--resources/src/mediawiki/mediawiki.Title.js11
-rw-r--r--resources/src/mediawiki/mediawiki.Uri.js41
-rw-r--r--resources/src/mediawiki/mediawiki.apihelp.css86
-rw-r--r--resources/src/mediawiki/mediawiki.apipretty.css11
-rw-r--r--resources/src/mediawiki/mediawiki.confirmCloseWindow.js68
-rw-r--r--resources/src/mediawiki/mediawiki.content.json.css18
-rw-r--r--resources/src/mediawiki/mediawiki.cookie.js25
-rw-r--r--resources/src/mediawiki/mediawiki.debug.js9
-rw-r--r--resources/src/mediawiki/mediawiki.debug.profile.css45
-rw-r--r--resources/src/mediawiki/mediawiki.debug.profile.js556
-rw-r--r--resources/src/mediawiki/mediawiki.errorLogger.js49
-rw-r--r--resources/src/mediawiki/mediawiki.feedback.css13
-rw-r--r--resources/src/mediawiki/mediawiki.feedback.js699
-rw-r--r--resources/src/mediawiki/mediawiki.filewarning.js68
-rw-r--r--resources/src/mediawiki/mediawiki.filewarning.less29
-rw-r--r--resources/src/mediawiki/mediawiki.helplink.less11
-rw-r--r--resources/src/mediawiki/mediawiki.hlist.js30
-rw-r--r--resources/src/mediawiki/mediawiki.htmlform.js38
-rw-r--r--resources/src/mediawiki/mediawiki.inspect.js24
-rw-r--r--resources/src/mediawiki/mediawiki.jqueryMsg.js69
-rw-r--r--resources/src/mediawiki/mediawiki.js862
-rw-r--r--resources/src/mediawiki/mediawiki.notification.js2
-rw-r--r--resources/src/mediawiki/mediawiki.pager.tablePager.less32
-rw-r--r--resources/src/mediawiki/mediawiki.searchSuggest.js8
-rw-r--r--resources/src/mediawiki/mediawiki.sectionAnchor.css3
-rw-r--r--resources/src/mediawiki/mediawiki.startUp.js11
-rw-r--r--resources/src/mediawiki/mediawiki.template.js123
-rw-r--r--resources/src/mediawiki/mediawiki.template.mustache.js14
-rw-r--r--resources/src/mediawiki/mediawiki.user.js101
-rw-r--r--resources/src/mediawiki/mediawiki.userSuggest.js41
-rw-r--r--resources/src/mediawiki/mediawiki.util.js73
1212 files changed, 27229 insertions, 17800 deletions
diff --git a/resources/Resources.php b/resources/Resources.php
index ec1c0fc4..2c0ca9d9 100644
--- a/resources/Resources.php
+++ b/resources/Resources.php
@@ -29,12 +29,19 @@ return array(
/**
* Special modules who have their own classes
*/
+ 'startup' => array( 'class' => 'ResourceLoaderStartUpModule' ),
// Scripts managed by the local wiki (stored in the MediaWiki namespace)
'site' => array( 'class' => 'ResourceLoaderSiteModule' ),
- 'noscript' => array( 'class' => 'ResourceLoaderNoscriptModule' ),
- 'startup' => array( 'class' => 'ResourceLoaderStartUpModule' ),
- 'filepage' => array( 'class' => 'ResourceLoaderFilePageModule' ),
+ 'noscript' => array(
+ 'class' => 'ResourceLoaderWikiModule',
+ 'styles' => array( 'MediaWiki:Noscript.css' ),
+ 'group' => 'noscript',
+ ),
+ 'filepage' => array(
+ 'class' => 'ResourceLoaderWikiModule',
+ 'styles' => array( 'MediaWiki:Filepage.css' ),
+ ),
'user.groups' => array( 'class' => 'ResourceLoaderUserGroupsModule' ),
// Scripts managed by the current user (stored in their user space)
@@ -44,6 +51,7 @@ return array(
'user.cssprefs' => array( 'class' => 'ResourceLoaderUserCSSPrefsModule' ),
// Populate mediawiki.user placeholders with information about the current user
+ 'user.defaults' => array( 'class' => 'ResourceLoaderUserDefaultsModule' ),
'user.options' => array( 'class' => 'ResourceLoaderUserOptionsModule' ),
'user.tokens' => array( 'class' => 'ResourceLoaderUserTokensModule' ),
@@ -93,6 +101,7 @@ return array(
),
),
'mediawiki.skinning.interface' => array(
+ 'class' => 'ResourceLoaderSkinModule',
// Used in the web installer. Test it after modifying this definition!
'styles' => array(
'resources/src/mediawiki.skinning/elements.css' => array( 'media' => 'screen' ),
@@ -120,14 +129,9 @@ return array(
/* jQuery */
'jquery' => array(
- 'scripts' => ( $GLOBALS['wgIncludejQueryMigrate'] ?
- array(
- 'resources/lib/jquery/jquery.js',
- 'resources/lib/jquery/jquery.migrate.js'
- ) :
- array(
- 'resources/lib/jquery/jquery.js'
- ) ),
+ 'scripts' => array(
+ 'resources/lib/jquery/jquery.js',
+ ),
'raw' => true,
'targets' => array( 'desktop', 'mobile' ),
),
@@ -181,7 +185,7 @@ return array(
'styles' => 'resources/lib/jquery.chosen/chosen.css',
),
'jquery.client' => array(
- 'scripts' => 'resources/src/jquery/jquery.client.js',
+ 'scripts' => 'resources/lib/jquery.client/jquery.client.js',
'targets' => array( 'desktop', 'mobile' ),
),
'jquery.color' => array(
@@ -244,14 +248,6 @@ return array(
'jquery.hoverIntent' => array(
'scripts' => 'resources/lib/jquery/jquery.hoverIntent.js',
),
- 'jquery.json' => array(
- // @deprecated since 1.24: Use the 'json' module and global JSON object instead.
- 'scripts' => array(
- 'resources/lib/jquery/jquery.json.js',
- 'resources/src/jquery.json-deprecate.js',
- ),
- 'targets' => array( 'mobile', 'desktop' ),
- ),
'jquery.localize' => array(
'scripts' => 'resources/src/jquery/jquery.localize.js',
),
@@ -277,8 +273,8 @@ return array(
'targets' => array( 'desktop', 'mobile' ),
),
'jquery.qunit' => array(
- 'scripts' => 'resources/lib/jquery/jquery.qunit.js',
- 'styles' => 'resources/lib/jquery/jquery.qunit.css',
+ 'scripts' => 'resources/lib/qunitjs/qunit.js',
+ 'styles' => 'resources/lib/qunitjs/qunit.css',
'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
@@ -318,6 +314,7 @@ return array(
),
'jquery.throttle-debounce' => array(
'scripts' => 'resources/lib/jquery/jquery.ba-throttle-debounce.js',
+ 'targets' => array( 'desktop', 'mobile' ),
),
'jquery.validate' => array(
'scripts' => 'resources/lib/jquery/jquery.validate.js',
@@ -769,16 +766,44 @@ return array(
'zh-cn' => 'resources/lib/moment/locale/zh-cn.js',
'zh-tw' => 'resources/lib/moment/locale/zh-tw.js',
),
+ 'targets' => array( 'desktop', 'mobile' ),
),
/* MediaWiki */
'mediawiki' => array(
- 'scripts' => 'resources/src/mediawiki/mediawiki.js',
+ // Keep maintenance/jsduck/eg-iframe.html in sync
+ 'scripts' => array(
+ 'resources/src/mediawiki/mediawiki.js',
+ 'resources/src/mediawiki/mediawiki.errorLogger.js',
+ 'resources/src/mediawiki/mediawiki.startUp.js',
+ ),
'debugScripts' => 'resources/src/mediawiki/mediawiki.log.js',
'raw' => true,
'targets' => array( 'desktop', 'mobile' ),
),
+ 'mediawiki.apihelp' => array(
+ 'styles' => 'resources/src/mediawiki/mediawiki.apihelp.css',
+ 'targets' => array( 'desktop' ),
+ 'dependencies' => 'mediawiki.hlist',
+ 'position' => 'top',
+ ),
+ 'mediawiki.template' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.template.js',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+ 'mediawiki.template.mustache' => array(
+ 'scripts' => array(
+ 'resources/lib/mustache/mustache.js',
+ 'resources/src/mediawiki/mediawiki.template.mustache.js',
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+ 'mediawiki.apipretty' => array(
+ 'styles' => 'resources/src/mediawiki/mediawiki.apipretty.css',
+ 'targets' => array( 'desktop', 'mobile' ),
+ 'position' => 'top',
+ ),
'mediawiki.api' => array(
'scripts' => 'resources/src/mediawiki.api/mediawiki.api.js',
'dependencies' => 'mediawiki.util',
@@ -798,12 +823,16 @@ return array(
'mediawiki.Title',
'user.tokens',
),
+ 'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.api.login' => array(
'scripts' => 'resources/src/mediawiki.api/mediawiki.api.login.js',
- 'dependencies' => array(
- 'mediawiki.api',
- ),
+ 'dependencies' => 'mediawiki.api',
+ ),
+ 'mediawiki.api.options' => array(
+ 'scripts' => 'resources/src/mediawiki.api/mediawiki.api.options.js',
+ 'dependencies' => 'mediawiki.api',
+ 'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.api.parse' => array(
'scripts' => 'resources/src/mediawiki.api/mediawiki.api.parse.js',
@@ -819,14 +848,18 @@ return array(
'mediawiki.content.json' => array(
'styles' => 'resources/src/mediawiki/mediawiki.content.json.css',
),
+ 'mediawiki.confirmCloseWindow' => array(
+ 'scripts' => array(
+ 'resources/src/mediawiki/mediawiki.confirmCloseWindow.js',
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
'mediawiki.debug' => array(
'scripts' => array(
'resources/src/mediawiki/mediawiki.debug.js',
- 'resources/src/mediawiki/mediawiki.debug.profile.js'
),
'styles' => array(
'resources/src/mediawiki/mediawiki.debug.less',
- 'resources/src/mediawiki/mediawiki.debug.profile.css'
),
'dependencies' => array(
'jquery.footHovzer',
@@ -845,48 +878,73 @@ return array(
'scripts' => 'resources/src/mediawiki/mediawiki.feedback.js',
'styles' => 'resources/src/mediawiki/mediawiki.feedback.css',
'dependencies' => array(
- 'mediawiki.api.edit',
+ 'mediawiki.messagePoster',
'mediawiki.Title',
- 'mediawiki.jqueryMsg',
- 'jquery.ui.dialog',
+ 'oojs-ui',
),
'messages' => array(
+ 'feedback-adding',
+ 'feedback-back',
+ 'feedback-bugcheck',
+ 'feedback-dialog-intro',
+ 'feedback-external-bug-report-button',
+ 'feedback-bugnew',
'feedback-bugornote',
- 'feedback-subject',
- 'feedback-message',
'feedback-cancel',
- 'feedback-submit',
- 'feedback-adding',
+ 'feedback-close',
+ 'feedback-dialog-title',
+ 'feedback-error-title',
'feedback-error1',
'feedback-error2',
'feedback-error3',
+ 'feedback-error4',
+ 'feedback-message',
+ 'feedback-subject',
+ 'feedback-submit',
+ 'feedback-terms',
+ 'feedback-termsofuse',
'feedback-thanks',
- 'feedback-close',
- 'feedback-bugcheck',
- 'feedback-bugnew',
+ 'feedback-thanks-title',
+ 'feedback-useragent'
),
),
- 'mediawiki.hidpi' => array(
- 'scripts' => 'resources/src/mediawiki/mediawiki.hidpi.js',
+
+ 'mediawiki.filewarning' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.filewarning.js',
+ 'styles' => 'resources/src/mediawiki/mediawiki.filewarning.less',
'dependencies' => array(
- 'jquery.hidpi',
+ 'oojs-ui',
+ ),
+ ),
+
+ 'mediawiki.helplink' => array(
+ 'styles' => array(
+ 'resources/src/mediawiki/mediawiki.helplink.less',
),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+ 'mediawiki.hidpi' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.hidpi.js',
+ 'dependencies' => 'jquery.hidpi',
'skipFunction' => 'resources/src/mediawiki.hidpi-skip.js',
'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.hlist' => array(
'styles' => 'resources/src/mediawiki/mediawiki.hlist.css',
'scripts' => 'resources/src/mediawiki/mediawiki.hlist.js',
- 'dependencies' => array(
- 'jquery.client',
- ),
+ 'dependencies' => 'jquery.client',
),
'mediawiki.htmlform' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.htmlform.js',
'dependencies' => array(
'jquery.mwExtension',
+ 'jquery.byteLimit',
+ ),
+ 'messages' => array(
+ 'htmlform-chosen-placeholder',
+ // @todo Load this message in content language
+ 'colon-separator',
),
- 'messages' => array( 'htmlform-chosen-placeholder' ),
),
'mediawiki.icon' => array(
'styles' => 'resources/src/mediawiki/mediawiki.icon.less',
@@ -899,6 +957,27 @@ return array(
),
'targets' => array( 'desktop', 'mobile' ),
),
+ 'mediawiki.messagePoster' => array(
+ 'scripts' => array(
+ 'resources/src/mediawiki.messagePoster/mediawiki.messagePoster.factory.js',
+ 'resources/src/mediawiki.messagePoster/mediawiki.messagePoster.MessagePoster.js',
+ ),
+ 'dependencies' => array(
+ 'oojs',
+ 'mediawiki.api',
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+ 'mediawiki.messagePoster.wikitext' => array(
+ 'scripts' => array(
+ 'resources/src/mediawiki.messagePoster/mediawiki.messagePoster.WikitextMessagePoster.js',
+ ),
+ 'dependencies' => array(
+ 'mediawiki.api.edit',
+ 'mediawiki.messagePoster',
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
'mediawiki.notification' => array(
'styles' => array(
'resources/src/mediawiki/mediawiki.notification.css',
@@ -906,9 +985,7 @@ return array(
=> array( 'media' => 'print' ),
),
'scripts' => 'resources/src/mediawiki/mediawiki.notification.js',
- 'dependencies' => array(
- 'mediawiki.page.startup',
- ),
+ 'dependencies' => 'mediawiki.page.startup',
'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.notify' => array(
@@ -930,9 +1007,15 @@ return array(
'jquery.client',
'jquery.placeholder',
'jquery.suggestions',
+ 'jquery.getAttrs',
'mediawiki.api',
),
),
+ 'mediawiki.sectionAnchor' => array(
+ // Back-compat to hide it on cached pages (T18691; Ie9e334e973; 2015-03-17)
+ 'styles' => 'resources/src/mediawiki/mediawiki.sectionAnchor.css',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
'mediawiki.Title' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.Title.js',
'dependencies' => array(
@@ -943,9 +1026,7 @@ return array(
),
'mediawiki.toc' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.toc.js',
- 'dependencies' => array(
- 'jquery.cookie',
- ),
+ 'dependencies' => 'jquery.cookie',
'messages' => array( 'showtoc', 'hidetoc' ),
'targets' => array( 'desktop', 'mobile' ),
),
@@ -964,6 +1045,13 @@ return array(
),
'targets' => array( 'desktop', 'mobile' ),
),
+ 'mediawiki.userSuggest' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.userSuggest.js',
+ 'dependencies' => array(
+ 'jquery.suggestions',
+ 'mediawiki.api'
+ )
+ ),
'mediawiki.util' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.util.js',
'dependencies' => array(
@@ -976,9 +1064,14 @@ return array(
),
'mediawiki.cookie' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.cookie.js',
- 'dependencies' => array(
- 'jquery.cookie',
- ),
+ 'dependencies' => 'jquery.cookie',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+ 'mediawiki.toolbar' => array(
+ 'class' => 'ResourceLoaderEditToolbarModule',
+ 'scripts' => 'resources/src/mediawiki.toolbar/toolbar.js',
+ 'styles' => 'resources/src/mediawiki.toolbar/toolbar.less',
+ 'position' => 'top',
),
/* MediaWiki Action */
@@ -988,7 +1081,6 @@ return array(
'styles' => 'resources/src/mediawiki.action/mediawiki.action.edit.css',
'dependencies' => array(
'mediawiki.action.edit.styles',
- 'mediawiki.action.edit.toolbar',
'jquery.textSelection',
'jquery.byteLimit',
),
@@ -998,10 +1090,6 @@ return array(
'styles' => 'resources/src/mediawiki.action/mediawiki.action.edit.styles.css',
'position' => 'top',
),
- 'mediawiki.action.edit.toolbar' => array(
- 'class' => 'ResourceLoaderEditToolbarModule',
- 'styles' => 'resources/src/mediawiki.action/mediawiki.action.edit.toolbar/mediawiki.action.edit.toolbar.less',
- ),
'mediawiki.action.edit.collapsibleFooter' => array(
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.edit.collapsibleFooter.js',
'styles' => 'resources/src/mediawiki.action/mediawiki.action.edit.collapsibleFooter.css',
@@ -1016,7 +1104,33 @@ return array(
'dependencies' => array(
'jquery.form',
'jquery.spinner',
+ 'jquery.textSelection',
+ 'mediawiki.api',
'mediawiki.action.history.diff',
+ 'mediawiki.util',
+ 'mediawiki.jqueryMsg',
+ ),
+ 'messages' => array(
+ // Keep the uses message keys in sync with EditPage#setHeaders
+ 'creating',
+ 'editconflict',
+ 'editing',
+ 'editingcomment',
+ 'editingsection',
+ 'pagetitle',
+ 'otherlanguages',
+ 'tooltip-p-lang',
+ 'summary-preview',
+ 'subject-preview',
+ 'parentheses',
+ 'previewerrortext',
+ ),
+ ),
+ 'mediawiki.action.edit.stash' => array(
+ 'scripts' => 'resources/src/mediawiki.action/mediawiki.action.edit.stash.js',
+ 'dependencies' => array(
+ 'jquery.getAttrs',
+ 'mediawiki.api',
),
),
'mediawiki.action.history' => array(
@@ -1025,7 +1139,12 @@ return array(
'group' => 'mediawiki.action.history',
),
'mediawiki.action.history.diff' => array(
- 'styles' => 'resources/src/mediawiki.action/mediawiki.action.history.diff.css',
+ 'styles' => array(
+ 'resources/src/mediawiki.action/mediawiki.action.history.diff.css',
+ 'resources/src/mediawiki.action/mediawiki.action.history.diff.print.css' => array(
+ 'media' => 'print'
+ ),
+ ),
'group' => 'mediawiki.action.history',
'targets' => array( 'desktop', 'mobile' ),
),
@@ -1034,6 +1153,7 @@ return array(
'dependencies' => array(
'mediawiki.util',
'mediawiki.page.startup',
+ 'user.options',
),
),
'mediawiki.action.view.metadata' => array(
@@ -1044,7 +1164,14 @@ return array(
'metadata-collapse',
),
),
+ 'mediawiki.action.view.categoryPage.styles' => array(
+ 'styles' => 'resources/src/mediawiki.action/mediawiki.action.view.categoryPage.less',
+ 'targets' => array( 'desktop', 'mobile' )
+ ),
'mediawiki.action.view.postEdit' => array(
+ 'templates' => array(
+ 'postEdit.html' => 'resources/src/mediawiki.action/templates/postEdit.html',
+ ),
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.postEdit.js',
'styles' => 'resources/src/mediawiki.action/mediawiki.action.view.postEdit.css',
'dependencies' => array(
@@ -1059,9 +1186,7 @@ return array(
),
'mediawiki.action.view.redirect' => array(
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.redirect.js',
- 'dependencies' => array(
- 'jquery.client',
- ),
+ 'dependencies' => 'jquery.client',
'position' => 'top',
),
'mediawiki.action.view.redirectPage' => array(
@@ -1075,10 +1200,12 @@ return array(
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js',
'dependencies' => array(
'jquery.textSelection',
- 'mediawiki.jqueryMsg'
+ 'mediawiki.jqueryMsg',
+ 'mediawiki.confirmCloseWindow',
),
'messages' => array(
'editwarning-warning',
+ // editwarning-warning uses {{int:prefs-editing}}
'prefs-editing'
),
),
@@ -1107,9 +1234,9 @@ return array(
'uk' => 'resources/src/mediawiki.language/languages/uk.js',
),
'dependencies' => array(
- 'mediawiki.language.data',
- 'mediawiki.cldr',
- ),
+ 'mediawiki.language.data',
+ 'mediawiki.cldr',
+ ),
'targets' => array( 'desktop', 'mobile' ),
'messages' => array(
'and',
@@ -1157,6 +1284,10 @@ return array(
'mediawiki.language.names' => array( 'class' => 'ResourceLoaderLanguageNamesModule' ),
+ 'mediawiki.language.specialCharacters' => array(
+ 'class' => 'ResourceLoaderSpecialCharacterDataModule'
+ ),
+
/* MediaWiki Libs */
'mediawiki.libs.jpegmeta' => array(
@@ -1167,6 +1298,9 @@ return array(
'mediawiki.page.gallery' => array(
'scripts' => 'resources/src/mediawiki.page/mediawiki.page.gallery.js',
+ 'dependencies' => array(
+ 'jquery.throttle-debounce',
+ )
),
'mediawiki.page.ready' => array(
'scripts' => 'resources/src/mediawiki.page/mediawiki.page.ready.js',
@@ -1181,9 +1315,7 @@ return array(
),
'mediawiki.page.startup' => array(
'scripts' => 'resources/src/mediawiki.page/mediawiki.page.startup.js',
- 'dependencies' => array(
- 'mediawiki.util',
- ),
+ 'dependencies' => 'mediawiki.util',
'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
@@ -1242,16 +1374,12 @@ return array(
'mediawiki.special.block' => array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.block.js',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.block.css',
- 'dependencies' => array(
- 'mediawiki.util',
- ),
+ 'dependencies' => 'mediawiki.util',
),
'mediawiki.special.changeemail' => array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.changeemail.js',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.changeemail.css',
- 'dependencies' => array(
- 'mediawiki.util',
- ),
+ 'dependencies' => 'mediawiki.util',
'messages' => array(
'email-address-validity-valid',
'email-address-validity-invalid',
@@ -1273,6 +1401,20 @@ return array(
'mediawiki.special.changeslist.enhanced' => array(
'styles' => 'resources/src/mediawiki.special/mediawiki.special.changeslist.enhanced.css',
),
+ 'mediawiki.special.edittags' => array(
+ 'scripts' => 'resources/src/mediawiki.special/mediawiki.special.edittags.js',
+ 'dependencies' => array(
+ 'jquery.chosen',
+ ),
+ 'messages' => array(
+ 'tags-edit-chosen-placeholder',
+ 'tags-edit-chosen-no-results',
+ ),
+ ),
+ 'mediawiki.special.edittags.styles' => array(
+ 'styles' => 'resources/src/mediawiki.special/mediawiki.special.edittags.css',
+ 'position' => 'top',
+ ),
'mediawiki.special.import' => array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.import.js',
),
@@ -1297,11 +1439,12 @@ return array(
),
'dependencies' => array(
'mediawiki.language',
+ 'mediawiki.confirmCloseWindow',
),
),
'mediawiki.special.recentchanges' => array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.recentchanges.js',
- 'dependencies' => array( 'mediawiki.special' ),
+ 'dependencies' => 'mediawiki.special',
'position' => 'top',
),
'mediawiki.special.search' => array(
@@ -1317,6 +1460,9 @@ return array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.undelete.js',
),
'mediawiki.special.upload' => array(
+ 'templates' => array(
+ 'thumbnail.html' => 'resources/src/mediawiki.special/templates/thumbnail.html',
+ ),
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.upload.js',
'messages' => array(
'widthheight',
@@ -1325,13 +1471,18 @@ return array(
'size-megabytes',
'size-gigabytes',
'largefileserver',
+ 'editwarning-warning',
+ // editwarning-warning uses {{int:prefs-editing}}
+ 'prefs-editing',
),
'dependencies' => array(
'jquery.spinner',
+ 'mediawiki.jqueryMsg',
'mediawiki.api',
'mediawiki.libs.jpegmeta',
'mediawiki.Title',
'mediawiki.util',
+ 'mediawiki.confirmCloseWindow',
),
),
'mediawiki.special.userlogin.common.styles' => array(
@@ -1401,9 +1552,7 @@ return array(
'colon-separator',
'javascripttest-pagetext-skins',
) ),
- 'dependencies' => array(
- 'mediawiki.Uri',
- ),
+ 'dependencies' => 'mediawiki.Uri',
'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
@@ -1437,9 +1586,7 @@ return array(
),
'mediawiki.legacy.protect' => array(
'scripts' => 'resources/src/mediawiki.legacy/protect.js',
- 'dependencies' => array(
- 'jquery.byteLimit',
- ),
+ 'dependencies' => 'jquery.byteLimit',
'messages' => array( 'protect-unchain-permissions' )
),
'mediawiki.legacy.shared' => array(
@@ -1455,9 +1602,7 @@ return array(
),
'mediawiki.legacy.wikibits' => array(
'scripts' => 'resources/src/mediawiki.legacy/wikibits.js',
- 'dependencies' => array(
- 'mediawiki.util',
- ),
+ 'dependencies' => 'mediawiki.util',
'position' => 'top',
),
@@ -1481,6 +1626,15 @@ return array(
'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
+ 'mediawiki.ui.radio' => array(
+ 'skinStyles' => array(
+ 'default' => array(
+ 'resources/src/mediawiki.ui/components/radio.less',
+ ),
+ ),
+ 'position' => 'top',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
// Lightweight module for anchor styles
'mediawiki.ui.anchor' => array(
'skinStyles' => array(
@@ -1510,6 +1664,25 @@ return array(
'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
+ 'mediawiki.ui.icon' => array(
+ 'skinStyles' => array(
+ 'default' => array(
+ 'resources/src/mediawiki.ui/components/icons.less',
+ ),
+ ),
+ 'position' => 'top',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+ // Lightweight module for text styles
+ 'mediawiki.ui.text' => array(
+ 'skinStyles' => array(
+ 'default' => array(
+ 'resources/src/mediawiki.ui/components/text.less',
+ ),
+ ),
+ 'position' => 'top',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
/* es5-shim */
'es5-shim' => array(
@@ -1540,29 +1713,37 @@ return array(
'scripts' => array(
'resources/lib/oojs-ui/oojs-ui.js',
),
- 'styles' => array(
- 'resources/lib/oojs-ui/oojs-ui.svg.css',
+ 'skinScripts' => array(
+ 'default' => 'resources/lib/oojs-ui/oojs-ui-mediawiki.js',
),
- 'skinStyles' => array(
- 'default' => 'resources/lib/oojs-ui/oojs-ui-apex.css',
- // FIXME As of July 2014, this is to be gone "in a couple of months".
- 'minerva' => 'resources/lib/oojs-ui/oojs-ui-minerva.css',
+ 'dependencies' => array(
+ 'es5-shim',
+ 'oojs',
+ 'oojs-ui.styles',
),
'messages' => array(
- 'ooui-outline-control-move-down',
- 'ooui-outline-control-move-up',
- 'ooui-outline-control-remove',
- 'ooui-toolbar-more',
'ooui-dialog-message-accept',
'ooui-dialog-message-reject',
+ 'ooui-dialog-process-continue',
'ooui-dialog-process-dismiss',
'ooui-dialog-process-error',
'ooui-dialog-process-retry',
+ 'ooui-outline-control-move-down',
+ 'ooui-outline-control-move-up',
+ 'ooui-outline-control-remove',
+ 'ooui-toolbar-more',
+ 'ooui-toolgroup-collapse',
+ 'ooui-toolgroup-expand',
),
- 'dependencies' => array(
- 'es5-shim',
- 'oojs',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+
+ 'oojs-ui.styles' => array(
+ 'position' => 'top',
+ 'skinStyles' => array(
+ 'default' => 'resources/lib/oojs-ui/oojs-ui-mediawiki.css',
),
'targets' => array( 'desktop', 'mobile' ),
),
+
);
diff --git a/resources/assets/file-type-icons/COPYING b/resources/assets/file-type-icons/COPYING
index 136530a9..19a775a8 100644
--- a/resources/assets/file-type-icons/COPYING
+++ b/resources/assets/file-type-icons/COPYING
@@ -1,4 +1,4 @@
-The icons used here are derived from the crystalsvg icons in the the
+The icons used here are derived from the crystalsvg icons in the
pics/crystalsvg/ directory of kdelibs-3.4.0 they were modified on 2005-05-15
by Ævar Arnfjörð Bjarmason for use in MediaWiki.
diff --git a/resources/assets/poweredby_mediawiki_132x47.png b/resources/assets/poweredby_mediawiki_132x47.png
new file mode 100644
index 00000000..a784ecff
--- /dev/null
+++ b/resources/assets/poweredby_mediawiki_132x47.png
Binary files differ
diff --git a/resources/assets/poweredby_mediawiki_176x62.png b/resources/assets/poweredby_mediawiki_176x62.png
new file mode 100644
index 00000000..79708012
--- /dev/null
+++ b/resources/assets/poweredby_mediawiki_176x62.png
Binary files differ
diff --git a/resources/lib/jquery.client/AUTHORS.txt b/resources/lib/jquery.client/AUTHORS.txt
new file mode 100644
index 00000000..9f186cac
--- /dev/null
+++ b/resources/lib/jquery.client/AUTHORS.txt
@@ -0,0 +1,9 @@
+Trevor Parscal <trevorparscal@gmail.com>
+Timo Tijhof <krinklemail@gmail.com>
+Roan Kattouw <roan.kattouw@gmail.com>
+Derk-Jan Hartman <hartman.wiki@gmail.com>
+Bartosz Dziewoński <matma.rex@gmail.com>
+Rob Moen <rmoen@wikimedia.org>
+Ed Sanders <esanders@wikimedia.org>
+Alex Monk <krenair@gmail.com>
+James D. Forrester <jforrester@wikimedia.org>
diff --git a/resources/lib/jquery.client/LICENSE-MIT.txt b/resources/lib/jquery.client/LICENSE-MIT.txt
new file mode 100644
index 00000000..f149289d
--- /dev/null
+++ b/resources/lib/jquery.client/LICENSE-MIT.txt
@@ -0,0 +1,20 @@
+Copyright 2010-2015 jquery-client maintainers and other contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/resources/lib/jquery.client/README.md b/resources/lib/jquery.client/README.md
new file mode 100644
index 00000000..02b5dd41
--- /dev/null
+++ b/resources/lib/jquery.client/README.md
@@ -0,0 +1,6 @@
+[![Build Status](https://travis-ci.org/wikimedia/jquery-client.svg?branch=master)](https://travis-ci.org/wikimedia/jquery-client) [![npm](https://img.shields.io/npm/v/jquery-client.svg?style=flat)](https://www.npmjs.com/package/jquery-client)
+
+jQuery Client
+=================
+
+jQuery Client is a jQuery plugin for user-agent detection.
diff --git a/resources/src/jquery/jquery.client.js b/resources/lib/jquery.client/jquery.client.js
index 662a6887..1560c7d2 100644
--- a/resources/src/jquery/jquery.client.js
+++ b/resources/lib/jquery.client/jquery.client.js
@@ -1,3 +1,12 @@
+/*!
+ * jQuery Client v1.0.0
+ * https://www.mediawiki.org/wiki/JQuery_Client
+ *
+ * Copyright 2010-2015 jquery-client maintainers and other contributors.
+ * Released under the MIT license
+ * http://jquery-client.mit-license.org
+ */
+
/**
* User-agent detection
*
@@ -33,7 +42,7 @@
* }
*/
profile: function ( nav ) {
- /*jshint boss: true */
+ /*jshint boss:true */
if ( nav === undefined ) {
nav = window.navigator;
@@ -87,11 +96,11 @@
// Tanslations for conforming browser names
nameTranslations = [],
// Names of known layout engines
- layouts = ['gecko', 'konqueror', 'msie', 'trident', 'opera', 'webkit'],
+ layouts = ['gecko', 'konqueror', 'msie', 'trident', 'edge', 'opera', 'webkit'],
// Translations for conforming layout names
layoutTranslations = [ ['konqueror', 'khtml'], ['msie', 'trident'], ['opera', 'presto'] ],
// Names of supported layout engines for version number
- layoutVersions = ['applewebkit', 'gecko', 'trident'],
+ layoutVersions = ['applewebkit', 'gecko', 'trident', 'edge'],
// Names of known operating systems
platforms = ['win', 'wow64', 'mac', 'linux', 'sunos', 'solaris', 'iphone'],
// Translations for conforming operating system names
@@ -173,6 +182,13 @@
version = match[1];
}
}
+ // And IE 12's different lies about not being IE
+ if ( name === 'chrome' && ( match = ua.match( /\bedge\/([0-9\.]*)/ ) ) ) {
+ name = 'msie';
+ version = match[1];
+ layout = 'edge';
+ layoutversion = parseInt( match[1], 10 );
+ }
// And Amazon Silk's lies about being Android on mobile or Safari on desktop
if ( match = ua.match( /\bsilk\/([0-9.\-_]*)/ ) ) {
if ( match[1] ) {
@@ -236,7 +252,7 @@
* @return {boolean} The current browser is in the support map
*/
test: function ( map, profile, exactMatchOnly ) {
- /*jshint evil: true */
+ /*jshint evil:true */
var conditions, dir, i, op, val, j, pieceVersion, pieceVal, compare;
profile = $.isPlainObject( profile ) ? profile : $.client.profile();
@@ -285,7 +301,7 @@
}
}
// compare will be -1, 0 or 1, depending on comparison result
- if ( !( eval( '' + compare + op + '0' ) ) ) {
+ if ( !( eval( String( compare + op + '0' ) ) ) ) {
return false;
}
} else if ( typeof val === 'number' ) {
diff --git a/resources/lib/jquery.ui/themes/smoothness/PATCHES b/resources/lib/jquery.ui/themes/smoothness/PATCHES
new file mode 100644
index 00000000..53fbe1fc
--- /dev/null
+++ b/resources/lib/jquery.ui/themes/smoothness/PATCHES
@@ -0,0 +1,3 @@
+jquery.ui.theme.css
+* Removed ".ui-widget-content a { color: #222222; }" and
+ ".ui-widget-header a { color: #222222; }" due to bug T85857.
diff --git a/resources/lib/jquery.ui/themes/smoothness/jquery.ui.core.css b/resources/lib/jquery.ui/themes/smoothness/jquery.ui.core.css
index 2e088ca1..d4f7db3b 100644
--- a/resources/lib/jquery.ui/themes/smoothness/jquery.ui.core.css
+++ b/resources/lib/jquery.ui/themes/smoothness/jquery.ui.core.css
@@ -14,7 +14,7 @@
.ui-helper-hidden { display: none; }
.ui-helper-hidden-accessible { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; }
-.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; }
+.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; border-collapse: collapse; }
.ui-helper-clearfix:after { clear: both; }
.ui-helper-clearfix { zoom: 1; }
.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); }
diff --git a/resources/lib/jquery.ui/themes/smoothness/jquery.ui.theme.css b/resources/lib/jquery.ui/themes/smoothness/jquery.ui.theme.css
index d170081b..1d8b8a8f 100644
--- a/resources/lib/jquery.ui/themes/smoothness/jquery.ui.theme.css
+++ b/resources/lib/jquery.ui/themes/smoothness/jquery.ui.theme.css
@@ -18,9 +18,7 @@
.ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #aaaaaa; background: #ffffff url("images/ui-bg_flat_75_ffffff_40x100.png") 50% 50% repeat-x; color: #222222; }
-.ui-widget-content a { color: #222222; }
.ui-widget-header { border: 1px solid #aaaaaa; background: #cccccc url("images/ui-bg_highlight-soft_75_cccccc_1x100.png") 50% 50% repeat-x; color: #222222; font-weight: bold; }
-.ui-widget-header a { color: #222222; }
/* Interaction states
----------------------------------*/
@@ -245,4 +243,4 @@
/* Overlays */
.ui-widget-overlay { background: #aaaaaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); }
-.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; } \ No newline at end of file
+.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url("images/ui-bg_flat_0_aaaaaa_40x100.png") 50% 50% repeat-x; opacity: .3;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -khtml-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }
diff --git a/resources/lib/jquery/jquery.jStorage.js b/resources/lib/jquery/jquery.jStorage.js
index cc11aed1..45e19ac6 100644
--- a/resources/lib/jquery/jquery.jStorage.js
+++ b/resources/lib/jquery/jquery.jStorage.js
@@ -34,12 +34,15 @@
* For more information, please refer to <http://unlicense.org/>
*/
+/* global ActiveXObject: false */
+/* jshint browser: true */
+
(function() {
'use strict';
var
/* jStorage version */
- JSTORAGE_VERSION = '0.4.10',
+ JSTORAGE_VERSION = '0.4.12',
/* detect a dollar object or create one if not found */
$ = window.jQuery || window.$ || (window.$ = {}),
@@ -58,7 +61,7 @@
};
// Break if no JSON support was found
- if (!('parse' in JSON) || !('stringify' in JSON)) {
+ if (typeof JSON.parse !== 'function' || typeof JSON.stringify !== 'function') {
throw new Error('No JSON support found, include //cdnjs.cloudflare.com/ajax/libs/json2/20110223/json2.js to page');
}
@@ -536,16 +539,21 @@
return;
}
var pubelm,
- _pubsubCurrent = _pubsub_last;
+ _pubsubCurrent = _pubsub_last,
+ needFired = [];
for (i = len = _storage.__jstorage_meta.PubSub.length - 1; i >= 0; i--) {
pubelm = _storage.__jstorage_meta.PubSub[i];
if (pubelm[0] > _pubsub_last) {
_pubsubCurrent = pubelm[0];
- _fireSubscribers(pubelm[1], pubelm[2]);
+ needFired.unshift(pubelm);
}
}
+ for (i = needFired.length - 1; i >= 0; i--) {
+ _fireSubscribers(needFired[i][1], needFired[i][2]);
+ }
+
_pubsub_last = _pubsubCurrent;
}
@@ -653,8 +661,10 @@
switch (l) {
case 3:
h ^= (str.charCodeAt(i + 2) & 0xff) << 16;
+ /* falls through */
case 2:
h ^= (str.charCodeAt(i + 1) & 0xff) << 8;
+ /* falls through */
case 1:
h ^= (str.charCodeAt(i) & 0xff);
h = (((h & 0xffff) * 0x5bd1e995) + ((((h >>> 16) * 0x5bd1e995) & 0xffff) << 16));
@@ -983,4 +993,4 @@
// Initialize jStorage
_init();
-})(); \ No newline at end of file
+})();
diff --git a/resources/lib/jquery/jquery.js b/resources/lib/jquery/jquery.js
index 1c3aa822..6feb1108 100644
--- a/resources/lib/jquery/jquery.js
+++ b/resources/lib/jquery/jquery.js
@@ -1,5 +1,5 @@
/*!
- * jQuery JavaScript Library v1.11.2
+ * jQuery JavaScript Library v1.11.3
* http://jquery.com/
*
* Includes Sizzle.js
@@ -9,7 +9,7 @@
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2014-12-17T15:27Z
+ * Date: 2015-04-28T16:19Z
*/
(function( global, factory ) {
@@ -64,7 +64,7 @@ var support = {};
var
- version = "1.11.2",
+ version = "1.11.3",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
@@ -569,7 +569,12 @@ jQuery.each("Boolean Number String Function Array Date RegExp Object Error".spli
});
function isArraylike( obj ) {
- var length = obj.length,
+
+ // Support: iOS 8.2 (not reproducible in simulator)
+ // `in` check used to prevent JIT error (gh-2145)
+ // hasOwn isn't used here due to false negatives
+ // regarding Nodelist length in IE
+ var length = "length" in obj && obj.length,
type = jQuery.type( obj );
if ( type === "function" || jQuery.isWindow( obj ) ) {
diff --git a/resources/lib/jquery/jquery.json.js b/resources/lib/jquery/jquery.json.js
deleted file mode 100644
index 75953f4d..00000000
--- a/resources/lib/jquery/jquery.json.js
+++ /dev/null
@@ -1,199 +0,0 @@
-/**
- * jQuery JSON plugin 2.4.0
- *
- * @author Brantley Harris, 2009-2011
- * @author Timo Tijhof, 2011-2012
- * @source This plugin is heavily influenced by MochiKit's serializeJSON, which is
- * copyrighted 2005 by Bob Ippolito.
- * @source Brantley Harris wrote this plugin. It is based somewhat on the JSON.org
- * website's http://www.json.org/json2.js, which proclaims:
- * "NO WARRANTY EXPRESSED OR IMPLIED. USE AT YOUR OWN RISK.", a sentiment that
- * I uphold.
- * @license MIT License <http://www.opensource.org/licenses/mit-license.php>
- */
-(function ($) {
- 'use strict';
-
- var escape = /["\\\x00-\x1f\x7f-\x9f]/g,
- meta = {
- '\b': '\\b',
- '\t': '\\t',
- '\n': '\\n',
- '\f': '\\f',
- '\r': '\\r',
- '"' : '\\"',
- '\\': '\\\\'
- },
- hasOwn = Object.prototype.hasOwnProperty;
-
- /**
- * jQuery.toJSON
- * Converts the given argument into a JSON representation.
- *
- * @param o {Mixed} The json-serializable *thing* to be converted
- *
- * If an object has a toJSON prototype, that will be used to get the representation.
- * Non-integer/string keys are skipped in the object, as are keys that point to a
- * function.
- *
- */
- $.toJSON = typeof JSON === 'object' && JSON.stringify ? JSON.stringify : function (o) {
- if (o === null) {
- return 'null';
- }
-
- var pairs, k, name, val,
- type = $.type(o);
-
- if (type === 'undefined') {
- return undefined;
- }
-
- // Also covers instantiated Number and Boolean objects,
- // which are typeof 'object' but thanks to $.type, we
- // catch them here. I don't know whether it is right
- // or wrong that instantiated primitives are not
- // exported to JSON as an {"object":..}.
- // We choose this path because that's what the browsers did.
- if (type === 'number' || type === 'boolean') {
- return String(o);
- }
- if (type === 'string') {
- return $.quoteString(o);
- }
- if (typeof o.toJSON === 'function') {
- return $.toJSON(o.toJSON());
- }
- if (type === 'date') {
- var month = o.getUTCMonth() + 1,
- day = o.getUTCDate(),
- year = o.getUTCFullYear(),
- hours = o.getUTCHours(),
- minutes = o.getUTCMinutes(),
- seconds = o.getUTCSeconds(),
- milli = o.getUTCMilliseconds();
-
- if (month < 10) {
- month = '0' + month;
- }
- if (day < 10) {
- day = '0' + day;
- }
- if (hours < 10) {
- hours = '0' + hours;
- }
- if (minutes < 10) {
- minutes = '0' + minutes;
- }
- if (seconds < 10) {
- seconds = '0' + seconds;
- }
- if (milli < 100) {
- milli = '0' + milli;
- }
- if (milli < 10) {
- milli = '0' + milli;
- }
- return '"' + year + '-' + month + '-' + day + 'T' +
- hours + ':' + minutes + ':' + seconds +
- '.' + milli + 'Z"';
- }
-
- pairs = [];
-
- if ($.isArray(o)) {
- for (k = 0; k < o.length; k++) {
- pairs.push($.toJSON(o[k]) || 'null');
- }
- return '[' + pairs.join(',') + ']';
- }
-
- // Any other object (plain object, RegExp, ..)
- // Need to do typeof instead of $.type, because we also
- // want to catch non-plain objects.
- if (typeof o === 'object') {
- for (k in o) {
- // Only include own properties,
- // Filter out inherited prototypes
- if (hasOwn.call(o, k)) {
- // Keys must be numerical or string. Skip others
- type = typeof k;
- if (type === 'number') {
- name = '"' + k + '"';
- } else if (type === 'string') {
- name = $.quoteString(k);
- } else {
- continue;
- }
- type = typeof o[k];
-
- // Invalid values like these return undefined
- // from toJSON, however those object members
- // shouldn't be included in the JSON string at all.
- if (type !== 'function' && type !== 'undefined') {
- val = $.toJSON(o[k]);
- pairs.push(name + ':' + val);
- }
- }
- }
- return '{' + pairs.join(',') + '}';
- }
- };
-
- /**
- * jQuery.evalJSON
- * Evaluates a given json string.
- *
- * @param str {String}
- */
- $.evalJSON = typeof JSON === 'object' && JSON.parse ? JSON.parse : function (str) {
- /*jshint evil: true */
- return eval('(' + str + ')');
- };
-
- /**
- * jQuery.secureEvalJSON
- * Evals JSON in a way that is *more* secure.
- *
- * @param str {String}
- */
- $.secureEvalJSON = typeof JSON === 'object' && JSON.parse ? JSON.parse : function (str) {
- var filtered =
- str
- .replace(/\\["\\\/bfnrtu]/g, '@')
- .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
- .replace(/(?:^|:|,)(?:\s*\[)+/g, '');
-
- if (/^[\],:{}\s]*$/.test(filtered)) {
- /*jshint evil: true */
- return eval('(' + str + ')');
- }
- throw new SyntaxError('Error parsing JSON, source is not valid.');
- };
-
- /**
- * jQuery.quoteString
- * Returns a string-repr of a string, escaping quotes intelligently.
- * Mostly a support function for toJSON.
- * Examples:
- * >>> jQuery.quoteString('apple')
- * "apple"
- *
- * >>> jQuery.quoteString('"Where are we going?", she asked.')
- * "\"Where are we going?\", she asked."
- */
- $.quoteString = function (str) {
- if (str.match(escape)) {
- return '"' + str.replace(escape, function (a) {
- var c = meta[a];
- if (typeof c === 'string') {
- return c;
- }
- c = a.charCodeAt();
- return '\\u00' + Math.floor(c / 16).toString(16) + (c % 16).toString(16);
- }) + '"';
- }
- return '"' + str + '"';
- };
-
-}(jQuery));
diff --git a/resources/lib/jquery/jquery.migrate.js b/resources/lib/jquery/jquery.migrate.js
deleted file mode 100644
index 5b182366..00000000
--- a/resources/lib/jquery/jquery.migrate.js
+++ /dev/null
@@ -1,551 +0,0 @@
-/*!
- * jQuery Migrate - v1.2.1 - 2013-05-08
- * https://github.com/jquery/jquery-migrate
- * Copyright 2005, 2013 jQuery Foundation, Inc. and other contributors; Licensed MIT
- *
- * Patched for MediaWiki to add mw.track calls. --Krinkle 2014-04-14
- */
-(function( jQuery, window, undefined ) {
-// See http://bugs.jquery.com/ticket/13335
-// "use strict";
-
-
-var warnedAbout = {};
-
-// List of warnings already given; public read only
-jQuery.migrateWarnings = [];
-
-// Set to true to prevent console output; migrateWarnings still maintained
-// jQuery.migrateMute = false;
-
-// Show a message on the console so devs know we're active
-if ( !jQuery.migrateMute && window.console && window.console.log ) {
- window.console.log("JQMIGRATE: Logging is active");
-}
-
-// Set to false to disable traces that appear with warnings
-if ( jQuery.migrateTrace === undefined ) {
- jQuery.migrateTrace = true;
-}
-
-// Forget any warnings we've already given; public
-jQuery.migrateReset = function() {
- warnedAbout = {};
- jQuery.migrateWarnings.length = 0;
-};
-
-function migrateWarn( msg, key ) {
- var console = window.console;
- /*
- MediaWiki patch for tracking usage.
-
- Custom keys:
- - andSelf
- - attr-pass
- - attr-prop
- - bind-error
- - clean
- - create-html
- - data-events
- - die
- - event-ajax
- - event-global
- - event-hover
- - event-handle
- - input-type
- - json-invalid
- - live
- - sub
- - toggle-handle
-
- Prop keys:
- - attrFn
- - browser
- */
- mw.track( "jquery.migrate", key || "unknown" );
-
- if ( !warnedAbout[ msg ] ) {
- warnedAbout[ msg ] = true;
- jQuery.migrateWarnings.push( msg );
- if ( console && console.warn && !jQuery.migrateMute ) {
- console.warn( "JQMIGRATE: " + msg );
- if ( jQuery.migrateTrace && console.trace ) {
- console.trace();
- }
- }
- }
-}
-
-function migrateWarnProp( obj, prop, value, msg, key ) {
- if ( Object.defineProperty ) {
- // On ES5 browsers (non-oldIE), warn if the code tries to get prop;
- // allow property to be overwritten in case some other plugin wants it
- try {
- Object.defineProperty( obj, prop, {
- configurable: true,
- enumerable: true,
- get: function() {
- migrateWarn( msg, key || prop );
- return value;
- },
- set: function( newValue ) {
- migrateWarn( msg, key || prop );
- value = newValue;
- }
- });
- return;
- } catch( err ) {
- // IE8 is a dope about Object.defineProperty, can't warn there
- }
- }
-
- // Non-ES5 (or broken) browser; just set the property
- jQuery._definePropertyBroken = true;
- obj[ prop ] = value;
-}
-
-if ( document.compatMode === "BackCompat" ) {
- // jQuery has never supported or tested Quirks Mode
- migrateWarn( "jQuery is not compatible with Quirks Mode" );
-}
-
-
-var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn,
- oldAttr = jQuery.attr,
- valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
- function() { return null; },
- valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
- function() { return undefined; },
- rnoType = /^(?:input|button)$/i,
- rnoAttrNodeType = /^[238]$/,
- rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
- ruseDefault = /^(?:checked|selected)$/i;
-
-// jQuery.attrFn
-migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
-
-jQuery.attr = function( elem, name, value, pass ) {
- var lowerName = name.toLowerCase(),
- nType = elem && elem.nodeType;
-
- if ( pass ) {
- // Since pass is used internally, we only warn for new jQuery
- // versions where there isn't a pass arg in the formal params
- if ( oldAttr.length < 4 ) {
- migrateWarn("jQuery.fn.attr( props, pass ) is deprecated", "attr-pass" );
- }
- if ( elem && !rnoAttrNodeType.test( nType ) &&
- (attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
- return jQuery( elem )[ name ]( value );
- }
- }
-
- // Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
- // for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
- if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {
- migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8", "input-type");
- }
-
- // Restore boolHook for boolean property/attribute synchronization
- if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
- jQuery.attrHooks[ lowerName ] = {
- get: function( elem, name ) {
- // Align boolean attributes with corresponding properties
- // Fall back to attribute presence where some booleans are not supported
- var attrNode,
- property = jQuery.prop( elem, name );
- return property === true || typeof property !== "boolean" &&
- ( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
-
- name.toLowerCase() :
- undefined;
- },
- set: function( elem, value, name ) {
- var propName;
- if ( value === false ) {
- // Remove boolean attributes when set to false
- jQuery.removeAttr( elem, name );
- } else {
- // value is true since we know at this point it's type boolean and not false
- // Set boolean attributes to the same name and set the DOM property
- propName = jQuery.propFix[ name ] || name;
- if ( propName in elem ) {
- // Only set the IDL specifically if it already exists on the element
- elem[ propName ] = true;
- }
-
- elem.setAttribute( name, name.toLowerCase() );
- }
- return name;
- }
- };
-
- // Warn only for attributes that can remain distinct from their properties post-1.9
- if ( ruseDefault.test( lowerName ) ) {
- migrateWarn( "jQuery.fn.attr('" + lowerName + "') may use property instead of attribute", "attr-prop" );
- }
- }
-
- return oldAttr.call( jQuery, elem, name, value );
-};
-
-// attrHooks: value
-jQuery.attrHooks.value = {
- get: function( elem, name ) {
- var nodeName = ( elem.nodeName || "" ).toLowerCase();
- if ( nodeName === "button" ) {
- return valueAttrGet.apply( this, arguments );
- }
- if ( nodeName !== "input" && nodeName !== "option" ) {
- migrateWarn("jQuery.fn.attr('value') no longer gets properties", "attr-prop");
- }
- return name in elem ?
- elem.value :
- null;
- },
- set: function( elem, value ) {
- var nodeName = ( elem.nodeName || "" ).toLowerCase();
- if ( nodeName === "button" ) {
- return valueAttrSet.apply( this, arguments );
- }
- if ( nodeName !== "input" && nodeName !== "option" ) {
- migrateWarn("jQuery.fn.attr('value', val) no longer sets properties", "attr-prop");
- }
- // Does not return so that setAttribute is also used
- elem.value = value;
- }
-};
-
-
-var matched, browser,
- oldInit = jQuery.fn.init,
- oldParseJSON = jQuery.parseJSON,
- // Note: XSS check is done below after string is trimmed
- rquickExpr = /^([^<]*)(<[\w\W]+>)([^>]*)$/;
-
-// $(html) "looks like html" rule change
-jQuery.fn.init = function( selector, context, rootjQuery ) {
- var match;
-
- if ( selector && typeof selector === "string" && !jQuery.isPlainObject( context ) &&
- (match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {
- // This is an HTML string according to the "old" rules; is it still?
- if ( selector.charAt( 0 ) !== "<" ) {
- migrateWarn("$(html) HTML strings must start with '<' character", "create-html");
- }
- if ( match[ 3 ] ) {
- migrateWarn("$(html) HTML text after last tag is ignored", "create-html");
- }
- // Consistently reject any HTML-like string starting with a hash (#9521)
- // Note that this may break jQuery 1.6.x code that otherwise would work.
- if ( match[ 0 ].charAt( 0 ) === "#" ) {
- migrateWarn("HTML string cannot start with a '#' character", "create-html");
- jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
- }
- // Now process using loose rules; let pre-1.8 play too
- if ( context && context.context ) {
- // jQuery object as context; parseHTML expects a DOM object
- context = context.context;
- }
- if ( jQuery.parseHTML ) {
- return oldInit.call( this, jQuery.parseHTML( match[ 2 ], context, true ),
- context, rootjQuery );
- }
- }
- return oldInit.apply( this, arguments );
-};
-jQuery.fn.init.prototype = jQuery.fn;
-
-// Let $.parseJSON(falsy_value) return null
-jQuery.parseJSON = function( json ) {
- if ( !json && json !== null ) {
- migrateWarn("jQuery.parseJSON requires a valid JSON string", "json-invalid");
- return null;
- }
- return oldParseJSON.apply( this, arguments );
-};
-
-jQuery.uaMatch = function( ua ) {
- ua = ua.toLowerCase();
-
- var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
- /(webkit)[ \/]([\w.]+)/.exec( ua ) ||
- /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
- /(msie) ([\w.]+)/.exec( ua ) ||
- ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
- [];
-
- return {
- browser: match[ 1 ] || "",
- version: match[ 2 ] || "0"
- };
-};
-
-// Don't clobber any existing jQuery.browser in case it's different
-if ( !jQuery.browser ) {
- matched = jQuery.uaMatch( navigator.userAgent );
- browser = {};
-
- if ( matched.browser ) {
- browser[ matched.browser ] = true;
- browser.version = matched.version;
- }
-
- // Chrome is Webkit, but Webkit is also Safari.
- if ( browser.chrome ) {
- browser.webkit = true;
- } else if ( browser.webkit ) {
- browser.safari = true;
- }
-
- jQuery.browser = browser;
-}
-
-// Warn if the code tries to get jQuery.browser
-migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
-
-jQuery.sub = function() {
- function jQuerySub( selector, context ) {
- return new jQuerySub.fn.init( selector, context );
- }
- jQuery.extend( true, jQuerySub, this );
- jQuerySub.superclass = this;
- jQuerySub.fn = jQuerySub.prototype = this();
- jQuerySub.fn.constructor = jQuerySub;
- jQuerySub.sub = this.sub;
- jQuerySub.fn.init = function init( selector, context ) {
- if ( context && context instanceof jQuery && !(context instanceof jQuerySub) ) {
- context = jQuerySub( context );
- }
-
- return jQuery.fn.init.call( this, selector, context, rootjQuerySub );
- };
- jQuerySub.fn.init.prototype = jQuerySub.fn;
- var rootjQuerySub = jQuerySub(document);
- migrateWarn( "jQuery.sub() is deprecated", "sub" );
- return jQuerySub;
-};
-
-
-// Ensure that $.ajax gets the new parseJSON defined in core.js
-jQuery.ajaxSetup({
- converters: {
- "text json": jQuery.parseJSON
- }
-});
-
-
-var oldFnData = jQuery.fn.data;
-
-jQuery.fn.data = function( name ) {
- var ret, evt,
- elem = this[0];
-
- // Handles 1.7 which has this behavior and 1.8 which doesn't
- if ( elem && name === "events" && arguments.length === 1 ) {
- ret = jQuery.data( elem, name );
- evt = jQuery._data( elem, name );
- if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
- migrateWarn("Use of jQuery.fn.data('events') is deprecated", "data-events");
- return evt;
- }
- }
- return oldFnData.apply( this, arguments );
-};
-
-
-var rscriptType = /\/(java|ecma)script/i,
- oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack;
-
-jQuery.fn.andSelf = function() {
- migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()", "andSelf");
- return oldSelf.apply( this, arguments );
-};
-
-// Since jQuery.clean is used internally on older versions, we only shim if it's missing
-if ( !jQuery.clean ) {
- jQuery.clean = function( elems, context, fragment, scripts ) {
- // Set context per 1.8 logic
- context = context || document;
- context = !context.nodeType && context[0] || context;
- context = context.ownerDocument || context;
-
- migrateWarn("jQuery.clean() is deprecated", "clean");
-
- var i, elem, handleScript, jsTags,
- ret = [];
-
- jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
-
- // Complex logic lifted directly from jQuery 1.8
- if ( fragment ) {
- // Special handling of each script element
- handleScript = function( elem ) {
- // Check if we consider it executable
- if ( !elem.type || rscriptType.test( elem.type ) ) {
- // Detach the script and store it in the scripts array (if provided) or the fragment
- // Return truthy to indicate that it has been handled
- return scripts ?
- scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
- fragment.appendChild( elem );
- }
- };
-
- for ( i = 0; (elem = ret[i]) != null; i++ ) {
- // Check if we're done after handling an executable script
- if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
- // Append to fragment and handle embedded scripts
- fragment.appendChild( elem );
- if ( typeof elem.getElementsByTagName !== "undefined" ) {
- // handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
- jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
-
- // Splice the scripts into ret after their former ancestor and advance our index beyond them
- ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
- i += jsTags.length;
- }
- }
- }
- }
-
- return ret;
- };
-}
-
-var eventAdd = jQuery.event.add,
- eventRemove = jQuery.event.remove,
- eventTrigger = jQuery.event.trigger,
- oldToggle = jQuery.fn.toggle,
- oldLive = jQuery.fn.live,
- oldDie = jQuery.fn.die,
- ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
- rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
- rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
- hoverHack = function( events ) {
- if ( typeof( events ) !== "string" || jQuery.event.special.hover ) {
- return events;
- }
- if ( rhoverHack.test( events ) ) {
- migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'", "event-hover");
- }
- return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
- };
-
-// Event props removed in 1.9, put them back if needed; no practical way to warn them
-if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
- jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
-}
-
-// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
-if ( jQuery.event.dispatch ) {
- migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated", "event-handle" );
-}
-
-// Support for 'hover' pseudo-event and ajax event warnings
-jQuery.event.add = function( elem, types, handler, data, selector ){
- if ( elem !== document && rajaxEvent.test( types ) ) {
- migrateWarn( "AJAX events should be attached to document: " + types, "event-ajax" );
- }
- eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
-};
-jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
- eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
-};
-
-jQuery.fn.error = function() {
- var args = Array.prototype.slice.call( arguments, 0);
- migrateWarn("jQuery.fn.error() is deprecated", "bind-error");
- args.splice( 0, 0, "error" );
- if ( arguments.length ) {
- return this.bind.apply( this, args );
- }
- // error event should not bubble to window, although it does pre-1.7
- this.triggerHandler.apply( this, args );
- return this;
-};
-
-jQuery.fn.toggle = function( fn, fn2 ) {
-
- // Don't mess with animation or css toggles
- if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
- return oldToggle.apply( this, arguments );
- }
- migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated", "toggle-handle");
-
- // Save reference to arguments for access in closure
- var args = arguments,
- guid = fn.guid || jQuery.guid++,
- i = 0,
- toggler = function( event ) {
- // Figure out which function to execute
- var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
- jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
-
- // Make sure that clicks stop
- event.preventDefault();
-
- // and execute the function
- return args[ lastToggle ].apply( this, arguments ) || false;
- };
-
- // link all the functions, so any of them can unbind this click handler
- toggler.guid = guid;
- while ( i < args.length ) {
- args[ i++ ].guid = guid;
- }
-
- return this.click( toggler );
-};
-
-jQuery.fn.live = function( types, data, fn ) {
- migrateWarn("jQuery.fn.live() is deprecated", "live");
- if ( oldLive ) {
- return oldLive.apply( this, arguments );
- }
- jQuery( this.context ).on( types, this.selector, data, fn );
- return this;
-};
-
-jQuery.fn.die = function( types, fn ) {
- migrateWarn("jQuery.fn.die() is deprecated", "die");
- if ( oldDie ) {
- return oldDie.apply( this, arguments );
- }
- jQuery( this.context ).off( types, this.selector || "**", fn );
- return this;
-};
-
-// Turn global events into document-triggered events
-jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
- if ( !elem && !rajaxEvent.test( event ) ) {
- migrateWarn( "Global events are undocumented and deprecated", "event-global" );
- }
- return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
-};
-jQuery.each( ajaxEvents.split("|"),
- function( _, name ) {
- jQuery.event.special[ name ] = {
- setup: function() {
- var elem = this;
-
- // The document needs no shimming; must be !== for oldIE
- if ( elem !== document ) {
- jQuery.event.add( document, name + "." + jQuery.guid, function() {
- jQuery.event.trigger( name, null, elem, true );
- });
- jQuery._data( this, name, jQuery.guid++ );
- }
- return false;
- },
- teardown: function() {
- if ( this !== document ) {
- jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
- }
- return false;
- }
- };
- }
-);
-
-
-})( jQuery, window );
diff --git a/resources/lib/jquery/jquery.qunit.js b/resources/lib/jquery/jquery.qunit.js
deleted file mode 100644
index 0e279fde..00000000
--- a/resources/lib/jquery/jquery.qunit.js
+++ /dev/null
@@ -1,2288 +0,0 @@
-/*!
- * QUnit 1.14.0
- * http://qunitjs.com/
- *
- * Copyright 2013 jQuery Foundation and other contributors
- * Released under the MIT license
- * http://jquery.org/license
- *
- * Date: 2014-01-31T16:40Z
- */
-
-(function( window ) {
-
-var QUnit,
- assert,
- config,
- onErrorFnPrev,
- testId = 0,
- fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""),
- toString = Object.prototype.toString,
- hasOwn = Object.prototype.hasOwnProperty,
- // Keep a local reference to Date (GH-283)
- Date = window.Date,
- setTimeout = window.setTimeout,
- clearTimeout = window.clearTimeout,
- defined = {
- document: typeof window.document !== "undefined",
- setTimeout: typeof window.setTimeout !== "undefined",
- sessionStorage: (function() {
- var x = "qunit-test-string";
- try {
- sessionStorage.setItem( x, x );
- sessionStorage.removeItem( x );
- return true;
- } catch( e ) {
- return false;
- }
- }())
- },
- /**
- * Provides a normalized error string, correcting an issue
- * with IE 7 (and prior) where Error.prototype.toString is
- * not properly implemented
- *
- * Based on http://es5.github.com/#x15.11.4.4
- *
- * @param {String|Error} error
- * @return {String} error message
- */
- errorString = function( error ) {
- var name, message,
- errorString = error.toString();
- if ( errorString.substring( 0, 7 ) === "[object" ) {
- name = error.name ? error.name.toString() : "Error";
- message = error.message ? error.message.toString() : "";
- if ( name && message ) {
- return name + ": " + message;
- } else if ( name ) {
- return name;
- } else if ( message ) {
- return message;
- } else {
- return "Error";
- }
- } else {
- return errorString;
- }
- },
- /**
- * Makes a clone of an object using only Array or Object as base,
- * and copies over the own enumerable properties.
- *
- * @param {Object} obj
- * @return {Object} New object with only the own properties (recursively).
- */
- objectValues = function( obj ) {
- // Grunt 0.3.x uses an older version of jshint that still has jshint/jshint#392.
- /*jshint newcap: false */
- var key, val,
- vals = QUnit.is( "array", obj ) ? [] : {};
- for ( key in obj ) {
- if ( hasOwn.call( obj, key ) ) {
- val = obj[key];
- vals[key] = val === Object(val) ? objectValues(val) : val;
- }
- }
- return vals;
- };
-
-
-// Root QUnit object.
-// `QUnit` initialized at top of scope
-QUnit = {
-
- // call on start of module test to prepend name to all tests
- module: function( name, testEnvironment ) {
- config.currentModule = name;
- config.currentModuleTestEnvironment = testEnvironment;
- config.modules[name] = true;
- },
-
- asyncTest: function( testName, expected, callback ) {
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- QUnit.test( testName, expected, callback, true );
- },
-
- test: function( testName, expected, callback, async ) {
- var test,
- nameHtml = "<span class='test-name'>" + escapeText( testName ) + "</span>";
-
- if ( arguments.length === 2 ) {
- callback = expected;
- expected = null;
- }
-
- if ( config.currentModule ) {
- nameHtml = "<span class='module-name'>" + escapeText( config.currentModule ) + "</span>: " + nameHtml;
- }
-
- test = new Test({
- nameHtml: nameHtml,
- testName: testName,
- expected: expected,
- async: async,
- callback: callback,
- module: config.currentModule,
- moduleTestEnvironment: config.currentModuleTestEnvironment,
- stack: sourceFromStacktrace( 2 )
- });
-
- if ( !validTest( test ) ) {
- return;
- }
-
- test.queue();
- },
-
- // Specify the number of expected assertions to guarantee that failed test (no assertions are run at all) don't slip through.
- expect: function( asserts ) {
- if (arguments.length === 1) {
- config.current.expected = asserts;
- } else {
- return config.current.expected;
- }
- },
-
- start: function( count ) {
- // QUnit hasn't been initialized yet.
- // Note: RequireJS (et al) may delay onLoad
- if ( config.semaphore === undefined ) {
- QUnit.begin(function() {
- // This is triggered at the top of QUnit.load, push start() to the event loop, to allow QUnit.load to finish first
- setTimeout(function() {
- QUnit.start( count );
- });
- });
- return;
- }
-
- config.semaphore -= count || 1;
- // don't start until equal number of stop-calls
- if ( config.semaphore > 0 ) {
- return;
- }
- // ignore if start is called more often then stop
- if ( config.semaphore < 0 ) {
- config.semaphore = 0;
- QUnit.pushFailure( "Called start() while already started (QUnit.config.semaphore was 0 already)", null, sourceFromStacktrace(2) );
- return;
- }
- // A slight delay, to avoid any current callbacks
- if ( defined.setTimeout ) {
- setTimeout(function() {
- if ( config.semaphore > 0 ) {
- return;
- }
- if ( config.timeout ) {
- clearTimeout( config.timeout );
- }
-
- config.blocking = false;
- process( true );
- }, 13);
- } else {
- config.blocking = false;
- process( true );
- }
- },
-
- stop: function( count ) {
- config.semaphore += count || 1;
- config.blocking = true;
-
- if ( config.testTimeout && defined.setTimeout ) {
- clearTimeout( config.timeout );
- config.timeout = setTimeout(function() {
- QUnit.ok( false, "Test timed out" );
- config.semaphore = 1;
- QUnit.start();
- }, config.testTimeout );
- }
- }
-};
-
-// We use the prototype to distinguish between properties that should
-// be exposed as globals (and in exports) and those that shouldn't
-(function() {
- function F() {}
- F.prototype = QUnit;
- QUnit = new F();
- // Make F QUnit's constructor so that we can add to the prototype later
- QUnit.constructor = F;
-}());
-
-/**
- * Config object: Maintain internal state
- * Later exposed as QUnit.config
- * `config` initialized at top of scope
- */
-config = {
- // The queue of tests to run
- queue: [],
-
- // block until document ready
- blocking: true,
-
- // when enabled, show only failing tests
- // gets persisted through sessionStorage and can be changed in UI via checkbox
- hidepassed: false,
-
- // by default, run previously failed tests first
- // very useful in combination with "Hide passed tests" checked
- reorder: true,
-
- // by default, modify document.title when suite is done
- altertitle: true,
-
- // by default, scroll to top of the page when suite is done
- scrolltop: true,
-
- // when enabled, all tests must call expect()
- requireExpects: false,
-
- // add checkboxes that are persisted in the query-string
- // when enabled, the id is set to `true` as a `QUnit.config` property
- urlConfig: [
- {
- id: "noglobals",
- label: "Check for Globals",
- tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings."
- },
- {
- id: "notrycatch",
- label: "No try-catch",
- tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings."
- }
- ],
-
- // Set of all modules.
- modules: {},
-
- // logging callback queues
- begin: [],
- done: [],
- log: [],
- testStart: [],
- testDone: [],
- moduleStart: [],
- moduleDone: []
-};
-
-// Initialize more QUnit.config and QUnit.urlParams
-(function() {
- var i, current,
- location = window.location || { search: "", protocol: "file:" },
- params = location.search.slice( 1 ).split( "&" ),
- length = params.length,
- urlParams = {};
-
- if ( params[ 0 ] ) {
- for ( i = 0; i < length; i++ ) {
- current = params[ i ].split( "=" );
- current[ 0 ] = decodeURIComponent( current[ 0 ] );
-
- // allow just a key to turn on a flag, e.g., test.html?noglobals
- current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
- if ( urlParams[ current[ 0 ] ] ) {
- urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] );
- } else {
- urlParams[ current[ 0 ] ] = current[ 1 ];
- }
- }
- }
-
- QUnit.urlParams = urlParams;
-
- // String search anywhere in moduleName+testName
- config.filter = urlParams.filter;
-
- // Exact match of the module name
- config.module = urlParams.module;
-
- config.testNumber = [];
- if ( urlParams.testNumber ) {
-
- // Ensure that urlParams.testNumber is an array
- urlParams.testNumber = [].concat( urlParams.testNumber );
- for ( i = 0; i < urlParams.testNumber.length; i++ ) {
- current = urlParams.testNumber[ i ];
- config.testNumber.push( parseInt( current, 10 ) );
- }
- }
-
- // Figure out if we're running the tests from a server or not
- QUnit.isLocal = location.protocol === "file:";
-}());
-
-extend( QUnit, {
-
- config: config,
-
- // Initialize the configuration options
- init: function() {
- extend( config, {
- stats: { all: 0, bad: 0 },
- moduleStats: { all: 0, bad: 0 },
- started: +new Date(),
- updateRate: 1000,
- blocking: false,
- autostart: true,
- autorun: false,
- filter: "",
- queue: [],
- semaphore: 1
- });
-
- var tests, banner, result,
- qunit = id( "qunit" );
-
- if ( qunit ) {
- qunit.innerHTML =
- "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
- "<h2 id='qunit-banner'></h2>" +
- "<div id='qunit-testrunner-toolbar'></div>" +
- "<h2 id='qunit-userAgent'></h2>" +
- "<ol id='qunit-tests'></ol>";
- }
-
- tests = id( "qunit-tests" );
- banner = id( "qunit-banner" );
- result = id( "qunit-testresult" );
-
- if ( tests ) {
- tests.innerHTML = "";
- }
-
- if ( banner ) {
- banner.className = "";
- }
-
- if ( result ) {
- result.parentNode.removeChild( result );
- }
-
- if ( tests ) {
- result = document.createElement( "p" );
- result.id = "qunit-testresult";
- result.className = "result";
- tests.parentNode.insertBefore( result, tests );
- result.innerHTML = "Running...<br/>&nbsp;";
- }
- },
-
- // Resets the test setup. Useful for tests that modify the DOM.
- /*
- DEPRECATED: Use multiple tests instead of resetting inside a test.
- Use testStart or testDone for custom cleanup.
- This method will throw an error in 2.0, and will be removed in 2.1
- */
- reset: function() {
- var fixture = id( "qunit-fixture" );
- if ( fixture ) {
- fixture.innerHTML = config.fixture;
- }
- },
-
- // Safe object type checking
- is: function( type, obj ) {
- return QUnit.objectType( obj ) === type;
- },
-
- objectType: function( obj ) {
- if ( typeof obj === "undefined" ) {
- return "undefined";
- }
-
- // Consider: typeof null === object
- if ( obj === null ) {
- return "null";
- }
-
- var match = toString.call( obj ).match(/^\[object\s(.*)\]$/),
- type = match && match[1] || "";
-
- switch ( type ) {
- case "Number":
- if ( isNaN(obj) ) {
- return "nan";
- }
- return "number";
- case "String":
- case "Boolean":
- case "Array":
- case "Date":
- case "RegExp":
- case "Function":
- return type.toLowerCase();
- }
- if ( typeof obj === "object" ) {
- return "object";
- }
- return undefined;
- },
-
- push: function( result, actual, expected, message ) {
- if ( !config.current ) {
- throw new Error( "assertion outside test context, was " + sourceFromStacktrace() );
- }
-
- var output, source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: message,
- actual: actual,
- expected: expected
- };
-
- message = escapeText( message ) || ( result ? "okay" : "failed" );
- message = "<span class='test-message'>" + message + "</span>";
- output = message;
-
- if ( !result ) {
- expected = escapeText( QUnit.jsDump.parse(expected) );
- actual = escapeText( QUnit.jsDump.parse(actual) );
- output += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" + expected + "</pre></td></tr>";
-
- if ( actual !== expected ) {
- output += "<tr class='test-actual'><th>Result: </th><td><pre>" + actual + "</pre></td></tr>";
- output += "<tr class='test-diff'><th>Diff: </th><td><pre>" + QUnit.diff( expected, actual ) + "</pre></td></tr>";
- }
-
- source = sourceFromStacktrace();
-
- if ( source ) {
- details.source = source;
- output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
- }
-
- output += "</table>";
- }
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: !!result,
- message: output
- });
- },
-
- pushFailure: function( message, source, actual ) {
- if ( !config.current ) {
- throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
-
- var output,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: false,
- message: message
- };
-
- message = escapeText( message ) || "error";
- message = "<span class='test-message'>" + message + "</span>";
- output = message;
-
- output += "<table>";
-
- if ( actual ) {
- output += "<tr class='test-actual'><th>Result: </th><td><pre>" + escapeText( actual ) + "</pre></td></tr>";
- }
-
- if ( source ) {
- details.source = source;
- output += "<tr class='test-source'><th>Source: </th><td><pre>" + escapeText( source ) + "</pre></td></tr>";
- }
-
- output += "</table>";
-
- runLoggingCallbacks( "log", QUnit, details );
-
- config.current.assertions.push({
- result: false,
- message: output
- });
- },
-
- url: function( params ) {
- params = extend( extend( {}, QUnit.urlParams ), params );
- var key,
- querystring = "?";
-
- for ( key in params ) {
- if ( hasOwn.call( params, key ) ) {
- querystring += encodeURIComponent( key ) + "=" +
- encodeURIComponent( params[ key ] ) + "&";
- }
- }
- return window.location.protocol + "//" + window.location.host +
- window.location.pathname + querystring.slice( 0, -1 );
- },
-
- extend: extend,
- id: id,
- addEvent: addEvent,
- addClass: addClass,
- hasClass: hasClass,
- removeClass: removeClass
- // load, equiv, jsDump, diff: Attached later
-});
-
-/**
- * @deprecated: Created for backwards compatibility with test runner that set the hook function
- * into QUnit.{hook}, instead of invoking it and passing the hook function.
- * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here.
- * Doing this allows us to tell if the following methods have been overwritten on the actual
- * QUnit object.
- */
-extend( QUnit.constructor.prototype, {
-
- // Logging callbacks; all receive a single argument with the listed properties
- // run test/logs.html for any related changes
- begin: registerLoggingCallback( "begin" ),
-
- // done: { failed, passed, total, runtime }
- done: registerLoggingCallback( "done" ),
-
- // log: { result, actual, expected, message }
- log: registerLoggingCallback( "log" ),
-
- // testStart: { name }
- testStart: registerLoggingCallback( "testStart" ),
-
- // testDone: { name, failed, passed, total, runtime }
- testDone: registerLoggingCallback( "testDone" ),
-
- // moduleStart: { name }
- moduleStart: registerLoggingCallback( "moduleStart" ),
-
- // moduleDone: { name, failed, passed, total }
- moduleDone: registerLoggingCallback( "moduleDone" )
-});
-
-if ( !defined.document || document.readyState === "complete" ) {
- config.autorun = true;
-}
-
-QUnit.load = function() {
- runLoggingCallbacks( "begin", QUnit, {} );
-
- // Initialize the config, saving the execution queue
- var banner, filter, i, j, label, len, main, ol, toolbar, val, selection,
- urlConfigContainer, moduleFilter, userAgent,
- numModules = 0,
- moduleNames = [],
- moduleFilterHtml = "",
- urlConfigHtml = "",
- oldconfig = extend( {}, config );
-
- QUnit.init();
- extend(config, oldconfig);
-
- config.blocking = false;
-
- len = config.urlConfig.length;
-
- for ( i = 0; i < len; i++ ) {
- val = config.urlConfig[i];
- if ( typeof val === "string" ) {
- val = {
- id: val,
- label: val
- };
- }
- config[ val.id ] = QUnit.urlParams[ val.id ];
- if ( !val.value || typeof val.value === "string" ) {
- urlConfigHtml += "<input id='qunit-urlconfig-" + escapeText( val.id ) +
- "' name='" + escapeText( val.id ) +
- "' type='checkbox'" +
- ( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) +
- ( config[ val.id ] ? " checked='checked'" : "" ) +
- " title='" + escapeText( val.tooltip ) +
- "'><label for='qunit-urlconfig-" + escapeText( val.id ) +
- "' title='" + escapeText( val.tooltip ) + "'>" + val.label + "</label>";
- } else {
- urlConfigHtml += "<label for='qunit-urlconfig-" + escapeText( val.id ) +
- "' title='" + escapeText( val.tooltip ) +
- "'>" + val.label +
- ": </label><select id='qunit-urlconfig-" + escapeText( val.id ) +
- "' name='" + escapeText( val.id ) +
- "' title='" + escapeText( val.tooltip ) +
- "'><option></option>";
- selection = false;
- if ( QUnit.is( "array", val.value ) ) {
- for ( j = 0; j < val.value.length; j++ ) {
- urlConfigHtml += "<option value='" + escapeText( val.value[j] ) + "'" +
- ( config[ val.id ] === val.value[j] ?
- (selection = true) && " selected='selected'" :
- "" ) +
- ">" + escapeText( val.value[j] ) + "</option>";
- }
- } else {
- for ( j in val.value ) {
- if ( hasOwn.call( val.value, j ) ) {
- urlConfigHtml += "<option value='" + escapeText( j ) + "'" +
- ( config[ val.id ] === j ?
- (selection = true) && " selected='selected'" :
- "" ) +
- ">" + escapeText( val.value[j] ) + "</option>";
- }
- }
- }
- if ( config[ val.id ] && !selection ) {
- urlConfigHtml += "<option value='" + escapeText( config[ val.id ] ) +
- "' selected='selected' disabled='disabled'>" +
- escapeText( config[ val.id ] ) +
- "</option>";
- }
- urlConfigHtml += "</select>";
- }
- }
- for ( i in config.modules ) {
- if ( config.modules.hasOwnProperty( i ) ) {
- moduleNames.push(i);
- }
- }
- numModules = moduleNames.length;
- moduleNames.sort( function( a, b ) {
- return a.localeCompare( b );
- });
- moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label><select id='qunit-modulefilter' name='modulefilter'><option value='' " +
- ( config.module === undefined ? "selected='selected'" : "" ) +
- ">< All Modules ></option>";
-
-
- for ( i = 0; i < numModules; i++) {
- moduleFilterHtml += "<option value='" + escapeText( encodeURIComponent(moduleNames[i]) ) + "' " +
- ( config.module === moduleNames[i] ? "selected='selected'" : "" ) +
- ">" + escapeText(moduleNames[i]) + "</option>";
- }
- moduleFilterHtml += "</select>";
-
- // `userAgent` initialized at top of scope
- userAgent = id( "qunit-userAgent" );
- if ( userAgent ) {
- userAgent.innerHTML = navigator.userAgent;
- }
-
- // `banner` initialized at top of scope
- banner = id( "qunit-header" );
- if ( banner ) {
- banner.innerHTML = "<a href='" + QUnit.url({ filter: undefined, module: undefined, testNumber: undefined }) + "'>" + banner.innerHTML + "</a> ";
- }
-
- // `toolbar` initialized at top of scope
- toolbar = id( "qunit-testrunner-toolbar" );
- if ( toolbar ) {
- // `filter` initialized at top of scope
- filter = document.createElement( "input" );
- filter.type = "checkbox";
- filter.id = "qunit-filter-pass";
-
- addEvent( filter, "click", function() {
- var tmp,
- ol = id( "qunit-tests" );
-
- if ( filter.checked ) {
- ol.className = ol.className + " hidepass";
- } else {
- tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " ";
- ol.className = tmp.replace( / hidepass /, " " );
- }
- if ( defined.sessionStorage ) {
- if (filter.checked) {
- sessionStorage.setItem( "qunit-filter-passed-tests", "true" );
- } else {
- sessionStorage.removeItem( "qunit-filter-passed-tests" );
- }
- }
- });
-
- if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) {
- filter.checked = true;
- // `ol` initialized at top of scope
- ol = id( "qunit-tests" );
- ol.className = ol.className + " hidepass";
- }
- toolbar.appendChild( filter );
-
- // `label` initialized at top of scope
- label = document.createElement( "label" );
- label.setAttribute( "for", "qunit-filter-pass" );
- label.setAttribute( "title", "Only show tests and assertions that fail. Stored in sessionStorage." );
- label.innerHTML = "Hide passed tests";
- toolbar.appendChild( label );
-
- urlConfigContainer = document.createElement("span");
- urlConfigContainer.innerHTML = urlConfigHtml;
- // For oldIE support:
- // * Add handlers to the individual elements instead of the container
- // * Use "click" instead of "change" for checkboxes
- // * Fallback from event.target to event.srcElement
- addEvents( urlConfigContainer.getElementsByTagName("input"), "click", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.checked ?
- target.defaultValue || true :
- undefined;
- window.location = QUnit.url( params );
- });
- addEvents( urlConfigContainer.getElementsByTagName("select"), "change", function( event ) {
- var params = {},
- target = event.target || event.srcElement;
- params[ target.name ] = target.options[ target.selectedIndex ].value || undefined;
- window.location = QUnit.url( params );
- });
- toolbar.appendChild( urlConfigContainer );
-
- if (numModules > 1) {
- moduleFilter = document.createElement( "span" );
- moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
- moduleFilter.innerHTML = moduleFilterHtml;
- addEvent( moduleFilter.lastChild, "change", function() {
- var selectBox = moduleFilter.getElementsByTagName("select")[0],
- selectedModule = decodeURIComponent(selectBox.options[selectBox.selectedIndex].value);
-
- window.location = QUnit.url({
- module: ( selectedModule === "" ) ? undefined : selectedModule,
- // Remove any existing filters
- filter: undefined,
- testNumber: undefined
- });
- });
- toolbar.appendChild(moduleFilter);
- }
- }
-
- // `main` initialized at top of scope
- main = id( "qunit-fixture" );
- if ( main ) {
- config.fixture = main.innerHTML;
- }
-
- if ( config.autostart ) {
- QUnit.start();
- }
-};
-
-if ( defined.document ) {
- addEvent( window, "load", QUnit.load );
-}
-
-// `onErrorFnPrev` initialized at top of scope
-// Preserve other handlers
-onErrorFnPrev = window.onerror;
-
-// Cover uncaught exceptions
-// Returning true will suppress the default browser handler,
-// returning false will let it run.
-window.onerror = function ( error, filePath, linerNr ) {
- var ret = false;
- if ( onErrorFnPrev ) {
- ret = onErrorFnPrev( error, filePath, linerNr );
- }
-
- // Treat return value as window.onerror itself does,
- // Only do our handling if not suppressed.
- if ( ret !== true ) {
- if ( QUnit.config.current ) {
- if ( QUnit.config.current.ignoreGlobalErrors ) {
- return true;
- }
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- } else {
- QUnit.test( "global failure", extend( function() {
- QUnit.pushFailure( error, filePath + ":" + linerNr );
- }, { validTest: validTest } ) );
- }
- return false;
- }
-
- return ret;
-};
-
-function done() {
- config.autorun = true;
-
- // Log the last module results
- if ( config.previousModule ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- delete config.previousModule;
-
- var i, key,
- banner = id( "qunit-banner" ),
- tests = id( "qunit-tests" ),
- runtime = +new Date() - config.started,
- passed = config.stats.all - config.stats.bad,
- html = [
- "Tests completed in ",
- runtime,
- " milliseconds.<br/>",
- "<span class='passed'>",
- passed,
- "</span> assertions of <span class='total'>",
- config.stats.all,
- "</span> passed, <span class='failed'>",
- config.stats.bad,
- "</span> failed."
- ].join( "" );
-
- if ( banner ) {
- banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" );
- }
-
- if ( tests ) {
- id( "qunit-testresult" ).innerHTML = html;
- }
-
- if ( config.altertitle && defined.document && document.title ) {
- // show ✖ for good, ✔ for bad suite result in title
- // use escape sequences in case file gets loaded with non-utf-8-charset
- document.title = [
- ( config.stats.bad ? "\u2716" : "\u2714" ),
- document.title.replace( /^[\u2714\u2716] /i, "" )
- ].join( " " );
- }
-
- // clear own sessionStorage items if all tests passed
- if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) {
- // `key` & `i` initialized at top of scope
- for ( i = 0; i < sessionStorage.length; i++ ) {
- key = sessionStorage.key( i++ );
- if ( key.indexOf( "qunit-test-" ) === 0 ) {
- sessionStorage.removeItem( key );
- }
- }
- }
-
- // scroll back to top to show results
- if ( config.scrolltop && window.scrollTo ) {
- window.scrollTo(0, 0);
- }
-
- runLoggingCallbacks( "done", QUnit, {
- failed: config.stats.bad,
- passed: passed,
- total: config.stats.all,
- runtime: runtime
- });
-}
-
-/** @return Boolean: true if this test should be ran */
-function validTest( test ) {
- var include,
- filter = config.filter && config.filter.toLowerCase(),
- module = config.module && config.module.toLowerCase(),
- fullName = ( test.module + ": " + test.testName ).toLowerCase();
-
- // Internally-generated tests are always valid
- if ( test.callback && test.callback.validTest === validTest ) {
- delete test.callback.validTest;
- return true;
- }
-
- if ( config.testNumber.length > 0 ) {
- if ( inArray( test.testNumber, config.testNumber ) < 0 ) {
- return false;
- }
- }
-
- if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) {
- return false;
- }
-
- if ( !filter ) {
- return true;
- }
-
- include = filter.charAt( 0 ) !== "!";
- if ( !include ) {
- filter = filter.slice( 1 );
- }
-
- // If the filter matches, we need to honour include
- if ( fullName.indexOf( filter ) !== -1 ) {
- return include;
- }
-
- // Otherwise, do the opposite
- return !include;
-}
-
-// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions)
-// Later Safari and IE10 are supposed to support error.stack as well
-// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
-function extractStacktrace( e, offset ) {
- offset = offset === undefined ? 3 : offset;
-
- var stack, include, i;
-
- if ( e.stacktrace ) {
- // Opera
- return e.stacktrace.split( "\n" )[ offset + 3 ];
- } else if ( e.stack ) {
- // Firefox, Chrome
- stack = e.stack.split( "\n" );
- if (/^error$/i.test( stack[0] ) ) {
- stack.shift();
- }
- if ( fileName ) {
- include = [];
- for ( i = offset; i < stack.length; i++ ) {
- if ( stack[ i ].indexOf( fileName ) !== -1 ) {
- break;
- }
- include.push( stack[ i ] );
- }
- if ( include.length ) {
- return include.join( "\n" );
- }
- }
- return stack[ offset ];
- } else if ( e.sourceURL ) {
- // Safari, PhantomJS
- // hopefully one day Safari provides actual stacktraces
- // exclude useless self-reference for generated Error objects
- if ( /qunit.js$/.test( e.sourceURL ) ) {
- return;
- }
- // for actual exceptions, this is useful
- return e.sourceURL + ":" + e.line;
- }
-}
-function sourceFromStacktrace( offset ) {
- try {
- throw new Error();
- } catch ( e ) {
- return extractStacktrace( e, offset );
- }
-}
-
-/**
- * Escape text for attribute or text content.
- */
-function escapeText( s ) {
- if ( !s ) {
- return "";
- }
- s = s + "";
- // Both single quotes and double quotes (for attributes)
- return s.replace( /['"<>&]/g, function( s ) {
- switch( s ) {
- case "'":
- return "&#039;";
- case "\"":
- return "&quot;";
- case "<":
- return "&lt;";
- case ">":
- return "&gt;";
- case "&":
- return "&amp;";
- }
- });
-}
-
-function synchronize( callback, last ) {
- config.queue.push( callback );
-
- if ( config.autorun && !config.blocking ) {
- process( last );
- }
-}
-
-function process( last ) {
- function next() {
- process( last );
- }
- var start = new Date().getTime();
- config.depth = config.depth ? config.depth + 1 : 1;
-
- while ( config.queue.length && !config.blocking ) {
- if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) {
- config.queue.shift()();
- } else {
- setTimeout( next, 13 );
- break;
- }
- }
- config.depth--;
- if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
- done();
- }
-}
-
-function saveGlobal() {
- config.pollution = [];
-
- if ( config.noglobals ) {
- for ( var key in window ) {
- if ( hasOwn.call( window, key ) ) {
- // in Opera sometimes DOM element ids show up here, ignore them
- if ( /^qunit-test-output/.test( key ) ) {
- continue;
- }
- config.pollution.push( key );
- }
- }
- }
-}
-
-function checkPollution() {
- var newGlobals,
- deletedGlobals,
- old = config.pollution;
-
- saveGlobal();
-
- newGlobals = diff( config.pollution, old );
- if ( newGlobals.length > 0 ) {
- QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") );
- }
-
- deletedGlobals = diff( old, config.pollution );
- if ( deletedGlobals.length > 0 ) {
- QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") );
- }
-}
-
-// returns a new Array with the elements that are in a but not in b
-function diff( a, b ) {
- var i, j,
- result = a.slice();
-
- for ( i = 0; i < result.length; i++ ) {
- for ( j = 0; j < b.length; j++ ) {
- if ( result[i] === b[j] ) {
- result.splice( i, 1 );
- i--;
- break;
- }
- }
- }
- return result;
-}
-
-function extend( a, b ) {
- for ( var prop in b ) {
- if ( hasOwn.call( b, prop ) ) {
- // Avoid "Member not found" error in IE8 caused by messing with window.constructor
- if ( !( prop === "constructor" && a === window ) ) {
- if ( b[ prop ] === undefined ) {
- delete a[ prop ];
- } else {
- a[ prop ] = b[ prop ];
- }
- }
- }
- }
-
- return a;
-}
-
-/**
- * @param {HTMLElement} elem
- * @param {string} type
- * @param {Function} fn
- */
-function addEvent( elem, type, fn ) {
- if ( elem.addEventListener ) {
-
- // Standards-based browsers
- elem.addEventListener( type, fn, false );
- } else if ( elem.attachEvent ) {
-
- // support: IE <9
- elem.attachEvent( "on" + type, fn );
- } else {
-
- // Caller must ensure support for event listeners is present
- throw new Error( "addEvent() was called in a context without event listener support" );
- }
-}
-
-/**
- * @param {Array|NodeList} elems
- * @param {string} type
- * @param {Function} fn
- */
-function addEvents( elems, type, fn ) {
- var i = elems.length;
- while ( i-- ) {
- addEvent( elems[i], type, fn );
- }
-}
-
-function hasClass( elem, name ) {
- return (" " + elem.className + " ").indexOf(" " + name + " ") > -1;
-}
-
-function addClass( elem, name ) {
- if ( !hasClass( elem, name ) ) {
- elem.className += (elem.className ? " " : "") + name;
- }
-}
-
-function removeClass( elem, name ) {
- var set = " " + elem.className + " ";
- // Class name may appear multiple times
- while ( set.indexOf(" " + name + " ") > -1 ) {
- set = set.replace(" " + name + " " , " ");
- }
- // If possible, trim it for prettiness, but not necessarily
- elem.className = typeof set.trim === "function" ? set.trim() : set.replace(/^\s+|\s+$/g, "");
-}
-
-function id( name ) {
- return defined.document && document.getElementById && document.getElementById( name );
-}
-
-function registerLoggingCallback( key ) {
- return function( callback ) {
- config[key].push( callback );
- };
-}
-
-// Supports deprecated method of completely overwriting logging callbacks
-function runLoggingCallbacks( key, scope, args ) {
- var i, callbacks;
- if ( QUnit.hasOwnProperty( key ) ) {
- QUnit[ key ].call(scope, args );
- } else {
- callbacks = config[ key ];
- for ( i = 0; i < callbacks.length; i++ ) {
- callbacks[ i ].call( scope, args );
- }
- }
-}
-
-// from jquery.js
-function inArray( elem, array ) {
- if ( array.indexOf ) {
- return array.indexOf( elem );
- }
-
- for ( var i = 0, length = array.length; i < length; i++ ) {
- if ( array[ i ] === elem ) {
- return i;
- }
- }
-
- return -1;
-}
-
-function Test( settings ) {
- extend( this, settings );
- this.assertions = [];
- this.testNumber = ++Test.count;
-}
-
-Test.count = 0;
-
-Test.prototype = {
- init: function() {
- var a, b, li,
- tests = id( "qunit-tests" );
-
- if ( tests ) {
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml;
-
- // `a` initialized at top of scope
- a = document.createElement( "a" );
- a.innerHTML = "Rerun";
- a.href = QUnit.url({ testNumber: this.testNumber });
-
- li = document.createElement( "li" );
- li.appendChild( b );
- li.appendChild( a );
- li.className = "running";
- li.id = this.id = "qunit-test-output" + testId++;
-
- tests.appendChild( li );
- }
- },
- setup: function() {
- if (
- // Emit moduleStart when we're switching from one module to another
- this.module !== config.previousModule ||
- // They could be equal (both undefined) but if the previousModule property doesn't
- // yet exist it means this is the first test in a suite that isn't wrapped in a
- // module, in which case we'll just emit a moduleStart event for 'undefined'.
- // Without this, reporters can get testStart before moduleStart which is a problem.
- !hasOwn.call( config, "previousModule" )
- ) {
- if ( hasOwn.call( config, "previousModule" ) ) {
- runLoggingCallbacks( "moduleDone", QUnit, {
- name: config.previousModule,
- failed: config.moduleStats.bad,
- passed: config.moduleStats.all - config.moduleStats.bad,
- total: config.moduleStats.all
- });
- }
- config.previousModule = this.module;
- config.moduleStats = { all: 0, bad: 0 };
- runLoggingCallbacks( "moduleStart", QUnit, {
- name: this.module
- });
- }
-
- config.current = this;
-
- this.testEnvironment = extend({
- setup: function() {},
- teardown: function() {}
- }, this.moduleTestEnvironment );
-
- this.started = +new Date();
- runLoggingCallbacks( "testStart", QUnit, {
- name: this.testName,
- module: this.module
- });
-
- /*jshint camelcase:false */
-
-
- /**
- * Expose the current test environment.
- *
- * @deprecated since 1.12.0: Use QUnit.config.current.testEnvironment instead.
- */
- QUnit.current_testEnvironment = this.testEnvironment;
-
- /*jshint camelcase:true */
-
- if ( !config.pollution ) {
- saveGlobal();
- }
- if ( config.notrycatch ) {
- this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
- return;
- }
- try {
- this.testEnvironment.setup.call( this.testEnvironment, QUnit.assert );
- } catch( e ) {
- QUnit.pushFailure( "Setup failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- },
- run: function() {
- config.current = this;
-
- var running = id( "qunit-testresult" );
-
- if ( running ) {
- running.innerHTML = "Running: <br/>" + this.nameHtml;
- }
-
- if ( this.async ) {
- QUnit.stop();
- }
-
- this.callbackStarted = +new Date();
-
- if ( config.notrycatch ) {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- return;
- }
-
- try {
- this.callback.call( this.testEnvironment, QUnit.assert );
- this.callbackRuntime = +new Date() - this.callbackStarted;
- } catch( e ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
-
- QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
- // else next test will carry the responsibility
- saveGlobal();
-
- // Restart the tests if they're blocking
- if ( config.blocking ) {
- QUnit.start();
- }
- }
- },
- teardown: function() {
- config.current = this;
- if ( config.notrycatch ) {
- if ( typeof this.callbackRuntime === "undefined" ) {
- this.callbackRuntime = +new Date() - this.callbackStarted;
- }
- this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
- return;
- } else {
- try {
- this.testEnvironment.teardown.call( this.testEnvironment, QUnit.assert );
- } catch( e ) {
- QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + ( e.message || e ), extractStacktrace( e, 1 ) );
- }
- }
- checkPollution();
- },
- finish: function() {
- config.current = this;
- if ( config.requireExpects && this.expected === null ) {
- QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack );
- } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
- QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack );
- } else if ( this.expected === null && !this.assertions.length ) {
- QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack );
- }
-
- var i, assertion, a, b, time, li, ol,
- test = this,
- good = 0,
- bad = 0,
- tests = id( "qunit-tests" );
-
- this.runtime = +new Date() - this.started;
- config.stats.all += this.assertions.length;
- config.moduleStats.all += this.assertions.length;
-
- if ( tests ) {
- ol = document.createElement( "ol" );
- ol.className = "qunit-assert-list";
-
- for ( i = 0; i < this.assertions.length; i++ ) {
- assertion = this.assertions[i];
-
- li = document.createElement( "li" );
- li.className = assertion.result ? "pass" : "fail";
- li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" );
- ol.appendChild( li );
-
- if ( assertion.result ) {
- good++;
- } else {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
-
- // store result when possible
- if ( QUnit.config.reorder && defined.sessionStorage ) {
- if ( bad ) {
- sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad );
- } else {
- sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName );
- }
- }
-
- if ( bad === 0 ) {
- addClass( ol, "qunit-collapsed" );
- }
-
- // `b` initialized at top of scope
- b = document.createElement( "strong" );
- b.innerHTML = this.nameHtml + " <b class='counts'>(<b class='failed'>" + bad + "</b>, <b class='passed'>" + good + "</b>, " + this.assertions.length + ")</b>";
-
- addEvent(b, "click", function() {
- var next = b.parentNode.lastChild,
- collapsed = hasClass( next, "qunit-collapsed" );
- ( collapsed ? removeClass : addClass )( next, "qunit-collapsed" );
- });
-
- addEvent(b, "dblclick", function( e ) {
- var target = e && e.target ? e.target : window.event.srcElement;
- if ( target.nodeName.toLowerCase() === "span" || target.nodeName.toLowerCase() === "b" ) {
- target = target.parentNode;
- }
- if ( window.location && target.nodeName.toLowerCase() === "strong" ) {
- window.location = QUnit.url({ testNumber: test.testNumber });
- }
- });
-
- // `time` initialized at top of scope
- time = document.createElement( "span" );
- time.className = "runtime";
- time.innerHTML = this.runtime + " ms";
-
- // `li` initialized at top of scope
- li = id( this.id );
- li.className = bad ? "fail" : "pass";
- li.removeChild( li.firstChild );
- a = li.firstChild;
- li.appendChild( b );
- li.appendChild( a );
- li.appendChild( time );
- li.appendChild( ol );
-
- } else {
- for ( i = 0; i < this.assertions.length; i++ ) {
- if ( !this.assertions[i].result ) {
- bad++;
- config.stats.bad++;
- config.moduleStats.bad++;
- }
- }
- }
-
- runLoggingCallbacks( "testDone", QUnit, {
- name: this.testName,
- module: this.module,
- failed: bad,
- passed: this.assertions.length - bad,
- total: this.assertions.length,
- runtime: this.runtime,
- // DEPRECATED: this property will be removed in 2.0.0, use runtime instead
- duration: this.runtime
- });
-
- QUnit.reset();
-
- config.current = undefined;
- },
-
- queue: function() {
- var bad,
- test = this;
-
- synchronize(function() {
- test.init();
- });
- function run() {
- // each of these can by async
- synchronize(function() {
- test.setup();
- });
- synchronize(function() {
- test.run();
- });
- synchronize(function() {
- test.teardown();
- });
- synchronize(function() {
- test.finish();
- });
- }
-
- // `bad` initialized at top of scope
- // defer when previous test run passed, if storage is available
- bad = QUnit.config.reorder && defined.sessionStorage &&
- +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName );
-
- if ( bad ) {
- run();
- } else {
- synchronize( run, true );
- }
- }
-};
-
-// `assert` initialized at top of scope
-// Assert helpers
-// All of these must either call QUnit.push() or manually do:
-// - runLoggingCallbacks( "log", .. );
-// - config.current.assertions.push({ .. });
-assert = QUnit.assert = {
- /**
- * Asserts rough true-ish result.
- * @name ok
- * @function
- * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
- */
- ok: function( result, msg ) {
- if ( !config.current ) {
- throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) );
- }
- result = !!result;
- msg = msg || ( result ? "okay" : "failed" );
-
- var source,
- details = {
- module: config.current.module,
- name: config.current.testName,
- result: result,
- message: msg
- };
-
- msg = "<span class='test-message'>" + escapeText( msg ) + "</span>";
-
- if ( !result ) {
- source = sourceFromStacktrace( 2 );
- if ( source ) {
- details.source = source;
- msg += "<table><tr class='test-source'><th>Source: </th><td><pre>" +
- escapeText( source ) +
- "</pre></td></tr></table>";
- }
- }
- runLoggingCallbacks( "log", QUnit, details );
- config.current.assertions.push({
- result: result,
- message: msg
- });
- },
-
- /**
- * Assert that the first two arguments are equal, with an optional message.
- * Prints out both actual and expected values.
- * @name equal
- * @function
- * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" );
- */
- equal: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected == actual, actual, expected, message );
- },
-
- /**
- * @name notEqual
- * @function
- */
- notEqual: function( actual, expected, message ) {
- /*jshint eqeqeq:false */
- QUnit.push( expected != actual, actual, expected, message );
- },
-
- /**
- * @name propEqual
- * @function
- */
- propEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notPropEqual
- * @function
- */
- notPropEqual: function( actual, expected, message ) {
- actual = objectValues(actual);
- expected = objectValues(expected);
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name deepEqual
- * @function
- */
- deepEqual: function( actual, expected, message ) {
- QUnit.push( QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name notDeepEqual
- * @function
- */
- notDeepEqual: function( actual, expected, message ) {
- QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message );
- },
-
- /**
- * @name strictEqual
- * @function
- */
- strictEqual: function( actual, expected, message ) {
- QUnit.push( expected === actual, actual, expected, message );
- },
-
- /**
- * @name notStrictEqual
- * @function
- */
- notStrictEqual: function( actual, expected, message ) {
- QUnit.push( expected !== actual, actual, expected, message );
- },
-
- "throws": function( block, expected, message ) {
- var actual,
- expectedOutput = expected,
- ok = false;
-
- // 'expected' is optional
- if ( !message && typeof expected === "string" ) {
- message = expected;
- expected = null;
- }
-
- config.current.ignoreGlobalErrors = true;
- try {
- block.call( config.current.testEnvironment );
- } catch (e) {
- actual = e;
- }
- config.current.ignoreGlobalErrors = false;
-
- if ( actual ) {
-
- // we don't want to validate thrown error
- if ( !expected ) {
- ok = true;
- expectedOutput = null;
-
- // expected is an Error object
- } else if ( expected instanceof Error ) {
- ok = actual instanceof Error &&
- actual.name === expected.name &&
- actual.message === expected.message;
-
- // expected is a regexp
- } else if ( QUnit.objectType( expected ) === "regexp" ) {
- ok = expected.test( errorString( actual ) );
-
- // expected is a string
- } else if ( QUnit.objectType( expected ) === "string" ) {
- ok = expected === errorString( actual );
-
- // expected is a constructor
- } else if ( actual instanceof expected ) {
- ok = true;
-
- // expected is a validation function which returns true is validation passed
- } else if ( expected.call( {}, actual ) === true ) {
- expectedOutput = null;
- ok = true;
- }
-
- QUnit.push( ok, actual, expectedOutput, message );
- } else {
- QUnit.pushFailure( message, null, "No exception was thrown." );
- }
- }
-};
-
-/**
- * @deprecated since 1.8.0
- * Kept assertion helpers in root for backwards compatibility.
- */
-extend( QUnit.constructor.prototype, assert );
-
-/**
- * @deprecated since 1.9.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.constructor.prototype.raises = function() {
- QUnit.push( false, false, false, "QUnit.raises has been deprecated since 2012 (fad3c1ea), use QUnit.throws instead" );
-};
-
-/**
- * @deprecated since 1.0.0, replaced with error pushes since 1.3.0
- * Kept to avoid TypeErrors for undefined methods.
- */
-QUnit.constructor.prototype.equals = function() {
- QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" );
-};
-QUnit.constructor.prototype.same = function() {
- QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" );
-};
-
-// Test for equality any JavaScript type.
-// Author: Philippe Rathé <prathe@gmail.com>
-QUnit.equiv = (function() {
-
- // Call the o related callback with the given arguments.
- function bindCallbacks( o, callbacks, args ) {
- var prop = QUnit.objectType( o );
- if ( prop ) {
- if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
- return callbacks[ prop ].apply( callbacks, args );
- } else {
- return callbacks[ prop ]; // or undefined
- }
- }
- }
-
- // the real equiv function
- var innerEquiv,
- // stack to decide between skip/abort functions
- callers = [],
- // stack to avoiding loops from circular referencing
- parents = [],
- parentsB = [],
-
- getProto = Object.getPrototypeOf || function ( obj ) {
- /*jshint camelcase:false */
- return obj.__proto__;
- },
- callbacks = (function () {
-
- // for string, boolean, number and null
- function useStrictEquality( b, a ) {
- /*jshint eqeqeq:false */
- if ( b instanceof a.constructor || a instanceof b.constructor ) {
- // to catch short annotation VS 'new' annotation of a
- // declaration
- // e.g. var i = 1;
- // var j = new Number(1);
- return a == b;
- } else {
- return a === b;
- }
- }
-
- return {
- "string": useStrictEquality,
- "boolean": useStrictEquality,
- "number": useStrictEquality,
- "null": useStrictEquality,
- "undefined": useStrictEquality,
-
- "nan": function( b ) {
- return isNaN( b );
- },
-
- "date": function( b, a ) {
- return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
- },
-
- "regexp": function( b, a ) {
- return QUnit.objectType( b ) === "regexp" &&
- // the regex itself
- a.source === b.source &&
- // and its modifiers
- a.global === b.global &&
- // (gmi) ...
- a.ignoreCase === b.ignoreCase &&
- a.multiline === b.multiline &&
- a.sticky === b.sticky;
- },
-
- // - skip when the property is a method of an instance (OOP)
- // - abort otherwise,
- // initial === would have catch identical references anyway
- "function": function() {
- var caller = callers[callers.length - 1];
- return caller !== Object && typeof caller !== "undefined";
- },
-
- "array": function( b, a ) {
- var i, j, len, loop, aCircular, bCircular;
-
- // b could be an object literal here
- if ( QUnit.objectType( b ) !== "array" ) {
- return false;
- }
-
- len = a.length;
- if ( len !== b.length ) {
- // safe and faster
- return false;
- }
-
- // track reference to avoid circular references
- parents.push( a );
- parentsB.push( b );
- for ( i = 0; i < len; i++ ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- aCircular = parents[j] === a[i];
- bCircular = parentsB[j] === b[i];
- if ( aCircular || bCircular ) {
- if ( a[i] === b[i] || aCircular && bCircular ) {
- loop = true;
- } else {
- parents.pop();
- parentsB.pop();
- return false;
- }
- }
- }
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- parents.pop();
- parentsB.pop();
- return false;
- }
- }
- parents.pop();
- parentsB.pop();
- return true;
- },
-
- "object": function( b, a ) {
- /*jshint forin:false */
- var i, j, loop, aCircular, bCircular,
- // Default to true
- eq = true,
- aProperties = [],
- bProperties = [];
-
- // comparing constructors is more strict than using
- // instanceof
- if ( a.constructor !== b.constructor ) {
- // Allow objects with no prototype to be equivalent to
- // objects with Object as their constructor.
- if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) ||
- ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) {
- return false;
- }
- }
-
- // stack constructor before traversing properties
- callers.push( a.constructor );
-
- // track reference to avoid circular references
- parents.push( a );
- parentsB.push( b );
-
- // be strict: don't ensure hasOwnProperty and go deep
- for ( i in a ) {
- loop = false;
- for ( j = 0; j < parents.length; j++ ) {
- aCircular = parents[j] === a[i];
- bCircular = parentsB[j] === b[i];
- if ( aCircular || bCircular ) {
- if ( a[i] === b[i] || aCircular && bCircular ) {
- loop = true;
- } else {
- eq = false;
- break;
- }
- }
- }
- aProperties.push(i);
- if ( !loop && !innerEquiv(a[i], b[i]) ) {
- eq = false;
- break;
- }
- }
-
- parents.pop();
- parentsB.pop();
- callers.pop(); // unstack, we are done
-
- for ( i in b ) {
- bProperties.push( i ); // collect b's properties
- }
-
- // Ensures identical properties name
- return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
- }
- };
- }());
-
- innerEquiv = function() { // can take multiple arguments
- var args = [].slice.apply( arguments );
- if ( args.length < 2 ) {
- return true; // end transition
- }
-
- return (function( a, b ) {
- if ( a === b ) {
- return true; // catch the most you can
- } else if ( a === null || b === null || typeof a === "undefined" ||
- typeof b === "undefined" ||
- QUnit.objectType(a) !== QUnit.objectType(b) ) {
- return false; // don't lose time with error prone cases
- } else {
- return bindCallbacks(a, callbacks, [ b, a ]);
- }
-
- // apply transition with (1..n) arguments
- }( args[0], args[1] ) && innerEquiv.apply( this, args.splice(1, args.length - 1 )) );
- };
-
- return innerEquiv;
-}());
-
-/**
- * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com |
- * http://flesler.blogspot.com Licensed under BSD
- * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008
- *
- * @projectDescription Advanced and extensible data dumping for Javascript.
- * @version 1.0.0
- * @author Ariel Flesler
- * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html}
- */
-QUnit.jsDump = (function() {
- function quote( str ) {
- return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
- }
- function literal( o ) {
- return o + "";
- }
- function join( pre, arr, post ) {
- var s = jsDump.separator(),
- base = jsDump.indent(),
- inner = jsDump.indent(1);
- if ( arr.join ) {
- arr = arr.join( "," + s + inner );
- }
- if ( !arr ) {
- return pre + post;
- }
- return [ pre, inner + arr, base + post ].join(s);
- }
- function array( arr, stack ) {
- var i = arr.length, ret = new Array(i);
- this.up();
- while ( i-- ) {
- ret[i] = this.parse( arr[i] , undefined , stack);
- }
- this.down();
- return join( "[", ret, "]" );
- }
-
- var reName = /^function (\w+)/,
- jsDump = {
- // type is used mostly internally, you can fix a (custom)type in advance
- parse: function( obj, type, stack ) {
- stack = stack || [ ];
- var inStack, res,
- parser = this.parsers[ type || this.typeOf(obj) ];
-
- type = typeof parser;
- inStack = inArray( obj, stack );
-
- if ( inStack !== -1 ) {
- return "recursion(" + (inStack - stack.length) + ")";
- }
- if ( type === "function" ) {
- stack.push( obj );
- res = parser.call( this, obj, stack );
- stack.pop();
- return res;
- }
- return ( type === "string" ) ? parser : this.parsers.error;
- },
- typeOf: function( obj ) {
- var type;
- if ( obj === null ) {
- type = "null";
- } else if ( typeof obj === "undefined" ) {
- type = "undefined";
- } else if ( QUnit.is( "regexp", obj) ) {
- type = "regexp";
- } else if ( QUnit.is( "date", obj) ) {
- type = "date";
- } else if ( QUnit.is( "function", obj) ) {
- type = "function";
- } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) {
- type = "window";
- } else if ( obj.nodeType === 9 ) {
- type = "document";
- } else if ( obj.nodeType ) {
- type = "node";
- } else if (
- // native arrays
- toString.call( obj ) === "[object Array]" ||
- // NodeList objects
- ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) )
- ) {
- type = "array";
- } else if ( obj.constructor === Error.prototype.constructor ) {
- type = "error";
- } else {
- type = typeof obj;
- }
- return type;
- },
- separator: function() {
- return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&nbsp;" : " ";
- },
- // extra can be a number, shortcut for increasing-calling-decreasing
- indent: function( extra ) {
- if ( !this.multiline ) {
- return "";
- }
- var chr = this.indentChar;
- if ( this.HTML ) {
- chr = chr.replace( /\t/g, " " ).replace( / /g, "&nbsp;" );
- }
- return new Array( this.depth + ( extra || 0 ) ).join(chr);
- },
- up: function( a ) {
- this.depth += a || 1;
- },
- down: function( a ) {
- this.depth -= a || 1;
- },
- setParser: function( name, parser ) {
- this.parsers[name] = parser;
- },
- // The next 3 are exposed so you can use them
- quote: quote,
- literal: literal,
- join: join,
- //
- depth: 1,
- // This is the list of parsers, to modify them, use jsDump.setParser
- parsers: {
- window: "[Window]",
- document: "[Document]",
- error: function(error) {
- return "Error(\"" + error.message + "\")";
- },
- unknown: "[Unknown]",
- "null": "null",
- "undefined": "undefined",
- "function": function( fn ) {
- var ret = "function",
- // functions never have name in IE
- name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];
-
- if ( name ) {
- ret += " " + name;
- }
- ret += "( ";
-
- ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" );
- return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" );
- },
- array: array,
- nodelist: array,
- "arguments": array,
- object: function( map, stack ) {
- /*jshint forin:false */
- var ret = [ ], keys, key, val, i;
- QUnit.jsDump.up();
- keys = [];
- for ( key in map ) {
- keys.push( key );
- }
- keys.sort();
- for ( i = 0; i < keys.length; i++ ) {
- key = keys[ i ];
- val = map[ key ];
- ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) );
- }
- QUnit.jsDump.down();
- return join( "{", ret, "}" );
- },
- node: function( node ) {
- var len, i, val,
- open = QUnit.jsDump.HTML ? "&lt;" : "<",
- close = QUnit.jsDump.HTML ? "&gt;" : ">",
- tag = node.nodeName.toLowerCase(),
- ret = open + tag,
- attrs = node.attributes;
-
- if ( attrs ) {
- for ( i = 0, len = attrs.length; i < len; i++ ) {
- val = attrs[i].nodeValue;
- // IE6 includes all attributes in .attributes, even ones not explicitly set.
- // Those have values like undefined, null, 0, false, "" or "inherit".
- if ( val && val !== "inherit" ) {
- ret += " " + attrs[i].nodeName + "=" + QUnit.jsDump.parse( val, "attribute" );
- }
- }
- }
- ret += close;
-
- // Show content of TextNode or CDATASection
- if ( node.nodeType === 3 || node.nodeType === 4 ) {
- ret += node.nodeValue;
- }
-
- return ret + open + "/" + tag + close;
- },
- // function calls it internally, it's the arguments part of the function
- functionArgs: function( fn ) {
- var args,
- l = fn.length;
-
- if ( !l ) {
- return "";
- }
-
- args = new Array(l);
- while ( l-- ) {
- // 97 is 'a'
- args[l] = String.fromCharCode(97+l);
- }
- return " " + args.join( ", " ) + " ";
- },
- // object calls it internally, the key part of an item in a map
- key: quote,
- // function calls it internally, it's the content of the function
- functionCode: "[code]",
- // node calls it internally, it's an html attribute value
- attribute: quote,
- string: quote,
- date: quote,
- regexp: literal,
- number: literal,
- "boolean": literal
- },
- // if true, entities are escaped ( <, >, \t, space and \n )
- HTML: false,
- // indentation unit
- indentChar: " ",
- // if true, items in a collection, are separated by a \n, else just a space.
- multiline: true
- };
-
- return jsDump;
-}());
-
-/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
- *
- * Released under the MIT license.
- *
- * More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
- *
- * Usage: QUnit.diff(expected, actual)
- *
- * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
- */
-QUnit.diff = (function() {
- /*jshint eqeqeq:false, eqnull:true */
- function diff( o, n ) {
- var i,
- ns = {},
- os = {};
-
- for ( i = 0; i < n.length; i++ ) {
- if ( !hasOwn.call( ns, n[i] ) ) {
- ns[ n[i] ] = {
- rows: [],
- o: null
- };
- }
- ns[ n[i] ].rows.push( i );
- }
-
- for ( i = 0; i < o.length; i++ ) {
- if ( !hasOwn.call( os, o[i] ) ) {
- os[ o[i] ] = {
- rows: [],
- n: null
- };
- }
- os[ o[i] ].rows.push( i );
- }
-
- for ( i in ns ) {
- if ( hasOwn.call( ns, i ) ) {
- if ( ns[i].rows.length === 1 && hasOwn.call( os, i ) && os[i].rows.length === 1 ) {
- n[ ns[i].rows[0] ] = {
- text: n[ ns[i].rows[0] ],
- row: os[i].rows[0]
- };
- o[ os[i].rows[0] ] = {
- text: o[ os[i].rows[0] ],
- row: ns[i].rows[0]
- };
- }
- }
- }
-
- for ( i = 0; i < n.length - 1; i++ ) {
- if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null &&
- n[ i + 1 ] == o[ n[i].row + 1 ] ) {
-
- n[ i + 1 ] = {
- text: n[ i + 1 ],
- row: n[i].row + 1
- };
- o[ n[i].row + 1 ] = {
- text: o[ n[i].row + 1 ],
- row: i + 1
- };
- }
- }
-
- for ( i = n.length - 1; i > 0; i-- ) {
- if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null &&
- n[ i - 1 ] == o[ n[i].row - 1 ]) {
-
- n[ i - 1 ] = {
- text: n[ i - 1 ],
- row: n[i].row - 1
- };
- o[ n[i].row - 1 ] = {
- text: o[ n[i].row - 1 ],
- row: i - 1
- };
- }
- }
-
- return {
- o: o,
- n: n
- };
- }
-
- return function( o, n ) {
- o = o.replace( /\s+$/, "" );
- n = n.replace( /\s+$/, "" );
-
- var i, pre,
- str = "",
- out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ),
- oSpace = o.match(/\s+/g),
- nSpace = n.match(/\s+/g);
-
- if ( oSpace == null ) {
- oSpace = [ " " ];
- }
- else {
- oSpace.push( " " );
- }
-
- if ( nSpace == null ) {
- nSpace = [ " " ];
- }
- else {
- nSpace.push( " " );
- }
-
- if ( out.n.length === 0 ) {
- for ( i = 0; i < out.o.length; i++ ) {
- str += "<del>" + out.o[i] + oSpace[i] + "</del>";
- }
- }
- else {
- if ( out.n[0].text == null ) {
- for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) {
- str += "<del>" + out.o[n] + oSpace[n] + "</del>";
- }
- }
-
- for ( i = 0; i < out.n.length; i++ ) {
- if (out.n[i].text == null) {
- str += "<ins>" + out.n[i] + nSpace[i] + "</ins>";
- }
- else {
- // `pre` initialized at top of scope
- pre = "";
-
- for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) {
- pre += "<del>" + out.o[n] + oSpace[n] + "</del>";
- }
- str += " " + out.n[i].text + nSpace[i] + pre;
- }
- }
- }
-
- return str;
- };
-}());
-
-// For browser, export only select globals
-if ( typeof window !== "undefined" ) {
- extend( window, QUnit.constructor.prototype );
- window.QUnit = QUnit;
-}
-
-// For CommonJS environments, export everything
-if ( typeof module !== "undefined" && module.exports ) {
- module.exports = QUnit;
-}
-
-
-// Get a reference to the global object, like window in browsers
-}( (function() {
- return this;
-})() ));
diff --git a/resources/lib/moment/locale/af.js b/resources/lib/moment/locale/af.js
index 1b8c5207..2fb7adff 100644
--- a/resources/lib/moment/locale/af.js
+++ b/resources/lib/moment/locale/af.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('af', {
@@ -26,6 +26,7 @@
},
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -54,6 +55,7 @@
y : '\'n jaar',
yy : '%d jaar'
},
+ ordinalParse: /\d{1,2}(ste|de)/,
ordinal : function (number) {
return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de'); // Thanks to Joris Röling : https://github.com/jjupiter
},
diff --git a/resources/lib/moment/locale/ar-ma.js b/resources/lib/moment/locale/ar-ma.js
index 5b2095a8..7add1722 100644
--- a/resources/lib/moment/locale/ar-ma.js
+++ b/resources/lib/moment/locale/ar-ma.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('ar-ma', {
@@ -20,6 +20,7 @@
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
diff --git a/resources/lib/moment/locale/ar-sa.js b/resources/lib/moment/locale/ar-sa.js
index f7867eac..ea7e2f6b 100644
--- a/resources/lib/moment/locale/ar-sa.js
+++ b/resources/lib/moment/locale/ar-sa.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var symbolMap = {
@@ -43,6 +43,7 @@
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'HH:mm:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -79,7 +80,7 @@
yy : '%d سنوات'
},
preparse: function (string) {
- return string.replace(/[۰-۹]/g, function (match) {
+ return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
return numberMap[match];
}).replace(/،/g, ',');
},
diff --git a/resources/lib/moment/locale/ar.js b/resources/lib/moment/locale/ar.js
index 1791a6b3..d6450087 100644
--- a/resources/lib/moment/locale/ar.js
+++ b/resources/lib/moment/locale/ar.js
@@ -10,7 +10,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var symbolMap = {
@@ -76,6 +76,7 @@
weekdaysMin : 'ح_ن_ث_ر_خ_ج_س'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'HH:mm:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -112,7 +113,7 @@
yy : pluralize('y')
},
preparse: function (string) {
- return string.replace(/[۰-۹]/g, function (match) {
+ return string.replace(/[١٢٣٤٥٦٧٨٩٠]/g, function (match) {
return numberMap[match];
}).replace(/،/g, ',');
},
diff --git a/resources/lib/moment/locale/az.js b/resources/lib/moment/locale/az.js
index e82f6e11..d4d14342 100644
--- a/resources/lib/moment/locale/az.js
+++ b/resources/lib/moment/locale/az.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var suffixes = {
@@ -44,6 +44,7 @@
weekdaysMin : 'Bz_BE_ÇA_Çə_CA_Cü_Şə'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -83,6 +84,7 @@
return 'axşam';
}
},
+ ordinalParse: /\d{1,2}-(ıncı|inci|nci|üncü|ncı|uncu)/,
ordinal : function (number) {
if (number === 0) { // special case for zero
return number + '-ıncı';
diff --git a/resources/lib/moment/locale/be.js b/resources/lib/moment/locale/be.js
index fe3186a1..68a6f37c 100644
--- a/resources/lib/moment/locale/be.js
+++ b/resources/lib/moment/locale/be.js
@@ -10,7 +10,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function plural(word, num) {
@@ -71,6 +71,7 @@
weekdaysMin : 'нд_пн_ат_ср_чц_пт_сб'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D MMMM YYYY г.',
LLL : 'D MMMM YYYY г., LT',
@@ -127,6 +128,7 @@
}
},
+ ordinalParse: /\d{1,2}-(і|ы|га)/,
ordinal: function (number, period) {
switch (period) {
case 'M':
diff --git a/resources/lib/moment/locale/bg.js b/resources/lib/moment/locale/bg.js
index 41b1e3af..540e17b5 100644
--- a/resources/lib/moment/locale/bg.js
+++ b/resources/lib/moment/locale/bg.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('bg', {
@@ -19,6 +19,7 @@
weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'D.MM.YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -59,6 +60,7 @@
y : 'година',
yy : '%d години'
},
+ ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
ordinal : function (number) {
var lastDigit = number % 10,
last2Digits = number % 100;
diff --git a/resources/lib/moment/locale/bn.js b/resources/lib/moment/locale/bn.js
index 7e8ccfd5..e9549d99 100644
--- a/resources/lib/moment/locale/bn.js
+++ b/resources/lib/moment/locale/bn.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var symbolMap = {
@@ -44,6 +44,7 @@
weekdaysMin : 'রব_সম_মঙ্গ_বু_ব্রিহ_শু_শনি'.split('_'),
longDateFormat : {
LT : 'A h:mm সময়',
+ LTS : 'A h:mm:ss সময়',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY, LT',
diff --git a/resources/lib/moment/locale/bo.js b/resources/lib/moment/locale/bo.js
index 0d44e47f..cece8d13 100644
--- a/resources/lib/moment/locale/bo.js
+++ b/resources/lib/moment/locale/bo.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var symbolMap = {
@@ -44,6 +44,7 @@
weekdaysMin : 'ཉི་མ་_ཟླ་བ་_མིག་དམར་_ལྷག་པ་_ཕུར་བུ_པ་སངས་_སྤེན་པ་'.split('_'),
longDateFormat : {
LT : 'A h:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY, LT',
diff --git a/resources/lib/moment/locale/br.js b/resources/lib/moment/locale/br.js
index a4f1491d..1f8dd614 100644
--- a/resources/lib/moment/locale/br.js
+++ b/resources/lib/moment/locale/br.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function relativeTimeWithMutation(number, withoutSuffix, key) {
@@ -67,6 +67,7 @@
weekdaysMin : 'Su_Lu_Me_Mer_Ya_Gw_Sa'.split('_'),
longDateFormat : {
LT : 'h[e]mm A',
+ LTS : 'h[e]mm:ss A',
L : 'DD/MM/YYYY',
LL : 'D [a viz] MMMM YYYY',
LLL : 'D [a viz] MMMM YYYY LT',
@@ -95,6 +96,7 @@
y : 'ur bloaz',
yy : specialMutationForYears
},
+ ordinalParse: /\d{1,2}(añ|vet)/,
ordinal : function (number) {
var output = (number === 1) ? 'añ' : 'vet';
return number + output;
diff --git a/resources/lib/moment/locale/bs.js b/resources/lib/moment/locale/bs.js
index b9a58516..c59f46ba 100644
--- a/resources/lib/moment/locale/bs.js
+++ b/resources/lib/moment/locale/bs.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function translate(number, withoutSuffix, key) {
@@ -66,13 +66,14 @@
}
return moment.defineLocale('bs', {
- months : 'januar_februar_mart_april_maj_juni_juli_avgust_septembar_oktobar_novembar_decembar'.split('_'),
- monthsShort : 'jan._feb._mar._apr._maj._jun._jul._avg._sep._okt._nov._dec.'.split('_'),
+ months : 'januar_februar_mart_april_maj_juni_juli_august_septembar_oktobar_novembar_decembar'.split('_'),
+ monthsShort : 'jan._feb._mar._apr._maj._jun._jul._aug._sep._okt._nov._dec.'.split('_'),
weekdays : 'nedjelja_ponedjeljak_utorak_srijeda_četvrtak_petak_subota'.split('_'),
weekdaysShort : 'ned._pon._uto._sri._čet._pet._sub.'.split('_'),
weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'DD. MM. YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY LT',
@@ -129,6 +130,7 @@
y : 'godinu',
yy : translate
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/ca.js b/resources/lib/moment/locale/ca.js
index fd41ff54..4f0d3fe0 100644
--- a/resources/lib/moment/locale/ca.js
+++ b/resources/lib/moment/locale/ca.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('ca', {
@@ -19,6 +19,7 @@
weekdaysMin : 'Dg_Dl_Dt_Dc_Dj_Dv_Ds'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -57,7 +58,17 @@
y : 'un any',
yy : '%d anys'
},
- ordinal : '%dº',
+ ordinalParse: /\d{1,2}(r|n|t|è|a)/,
+ ordinal : function (number, period) {
+ var output = (number === 1) ? 'r' :
+ (number === 2) ? 'n' :
+ (number === 3) ? 'r' :
+ (number === 4) ? 't' : 'è';
+ if (period === 'w' || period === 'W') {
+ output = 'a';
+ }
+ return number + output;
+ },
week : {
dow : 1, // Monday is the first day of the week.
doy : 4 // The week that contains Jan 4th is the first week of the year.
diff --git a/resources/lib/moment/locale/cs.js b/resources/lib/moment/locale/cs.js
index 87dec552..b61658dc 100644
--- a/resources/lib/moment/locale/cs.js
+++ b/resources/lib/moment/locale/cs.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var months = 'leden_únor_březen_duben_květen_červen_červenec_srpen_září_říjen_listopad_prosinec'.split('_'),
@@ -87,7 +87,8 @@
weekdaysMin : 'ne_po_út_st_čt_pá_so'.split('_'),
longDateFormat : {
LT: 'H:mm',
- L : 'DD. MM. YYYY',
+ LTS : 'LT:ss',
+ L : 'DD.MM.YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY LT',
LLLL : 'dddd D. MMMM YYYY LT'
@@ -146,6 +147,7 @@
y : translate,
yy : translate
},
+ ordinalParse : /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/cv.js b/resources/lib/moment/locale/cv.js
index 138b6c15..ea8e314d 100644
--- a/resources/lib/moment/locale/cv.js
+++ b/resources/lib/moment/locale/cv.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('cv', {
@@ -19,6 +19,7 @@
weekdaysMin : 'вр_тн_ыт_юн_кç_эр_шм'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD-MM-YYYY',
LL : 'YYYY [çулхи] MMMM [уйăхĕн] D[-мĕшĕ]',
LLL : 'YYYY [çулхи] MMMM [уйăхĕн] D[-мĕшĕ], LT',
@@ -50,6 +51,7 @@
y : 'пĕр çул',
yy : '%d çул'
},
+ ordinalParse: /\d{1,2}-мĕш/,
ordinal : '%d-мĕш',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/cy.js b/resources/lib/moment/locale/cy.js
index 65fb356b..72b2f91d 100644
--- a/resources/lib/moment/locale/cy.js
+++ b/resources/lib/moment/locale/cy.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('cy', {
@@ -20,6 +20,7 @@
// time formats are the same as en-gb
longDateFormat: {
LT: 'HH:mm',
+ LTS : 'LT:ss',
L: 'DD/MM/YYYY',
LL: 'D MMMM YYYY',
LLL: 'D MMMM YYYY LT',
@@ -48,6 +49,7 @@
y: 'blwyddyn',
yy: '%d flynedd'
},
+ ordinalParse: /\d{1,2}(fed|ain|af|il|ydd|ed|eg)/,
// traditional ordinal numbers above 31 are not commonly used in colloquial Welsh
ordinal: function (number) {
var b = number,
diff --git a/resources/lib/moment/locale/da.js b/resources/lib/moment/locale/da.js
index 5e9ef96d..686ce009 100644
--- a/resources/lib/moment/locale/da.js
+++ b/resources/lib/moment/locale/da.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('da', {
@@ -19,6 +19,7 @@
weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY LT',
@@ -47,6 +48,7 @@
y : 'et år',
yy : '%d år'
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/de-at.js b/resources/lib/moment/locale/de-at.js
index ff715f89..c9826382 100644
--- a/resources/lib/moment/locale/de-at.js
+++ b/resources/lib/moment/locale/de-at.js
@@ -10,7 +10,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function processRelativeTime(number, withoutSuffix, key, isFuture) {
@@ -34,19 +34,20 @@
weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
longDateFormat : {
- LT: 'HH:mm [Uhr]',
+ LT: 'HH:mm',
+ LTS: 'HH:mm:ss',
L : 'DD.MM.YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY LT',
LLLL : 'dddd, D. MMMM YYYY LT'
},
calendar : {
- sameDay: '[Heute um] LT',
+ sameDay: '[Heute um] LT [Uhr]',
sameElse: 'L',
- nextDay: '[Morgen um] LT',
- nextWeek: 'dddd [um] LT',
- lastDay: '[Gestern um] LT',
- lastWeek: '[letzten] dddd [um] LT'
+ nextDay: '[Morgen um] LT [Uhr]',
+ nextWeek: 'dddd [um] LT [Uhr]',
+ lastDay: '[Gestern um] LT [Uhr]',
+ lastWeek: '[letzten] dddd [um] LT [Uhr]'
},
relativeTime : {
future : 'in %s',
@@ -63,6 +64,7 @@
y : processRelativeTime,
yy : processRelativeTime
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/de.js b/resources/lib/moment/locale/de.js
index 11ab9ace..f6d89a90 100644
--- a/resources/lib/moment/locale/de.js
+++ b/resources/lib/moment/locale/de.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function processRelativeTime(number, withoutSuffix, key, isFuture) {
@@ -33,19 +33,20 @@
weekdaysShort : 'So._Mo._Di._Mi._Do._Fr._Sa.'.split('_'),
weekdaysMin : 'So_Mo_Di_Mi_Do_Fr_Sa'.split('_'),
longDateFormat : {
- LT: 'HH:mm [Uhr]',
+ LT: 'HH:mm',
+ LTS: 'HH:mm:ss',
L : 'DD.MM.YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY LT',
LLLL : 'dddd, D. MMMM YYYY LT'
},
calendar : {
- sameDay: '[Heute um] LT',
+ sameDay: '[Heute um] LT [Uhr]',
sameElse: 'L',
- nextDay: '[Morgen um] LT',
- nextWeek: 'dddd [um] LT',
- lastDay: '[Gestern um] LT',
- lastWeek: '[letzten] dddd [um] LT'
+ nextDay: '[Morgen um] LT [Uhr]',
+ nextWeek: 'dddd [um] LT [Uhr]',
+ lastDay: '[Gestern um] LT [Uhr]',
+ lastWeek: '[letzten] dddd [um] LT [Uhr]'
},
relativeTime : {
future : 'in %s',
@@ -62,6 +63,7 @@
y : processRelativeTime,
yy : processRelativeTime
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/el.js b/resources/lib/moment/locale/el.js
index eb8eb1a9..6dc769e2 100644
--- a/resources/lib/moment/locale/el.js
+++ b/resources/lib/moment/locale/el.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('el', {
@@ -38,6 +38,7 @@
meridiemParse : /[ΠΜ]\.?Μ?\.?/i,
longDateFormat : {
LT : 'h:mm A',
+ LTS : 'h:mm:ss A',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -71,7 +72,7 @@
relativeTime : {
future : 'σε %s',
past : '%s πριν',
- s : 'δευτερόλεπτα',
+ s : 'λίγα δευτερόλεπτα',
m : 'ένα λεπτό',
mm : '%d λεπτά',
h : 'μία ώρα',
@@ -83,9 +84,8 @@
y : 'ένας χρόνος',
yy : '%d χρόνια'
},
- ordinal : function (number) {
- return number + 'η';
- },
+ ordinalParse: /\d{1,2}η/,
+ ordinal: '%dη',
week : {
dow : 1, // Monday is the first day of the week.
doy : 4 // The week that contains Jan 4st is the first week of the year.
diff --git a/resources/lib/moment/locale/en-au.js b/resources/lib/moment/locale/en-au.js
index 75ad34a1..a382b0ae 100644
--- a/resources/lib/moment/locale/en-au.js
+++ b/resources/lib/moment/locale/en-au.js
@@ -7,7 +7,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('en-au', {
@@ -18,6 +18,7 @@
weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
longDateFormat : {
LT : 'h:mm A',
+ LTS : 'h:mm:ss A',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -46,6 +47,7 @@
y : 'a year',
yy : '%d years'
},
+ ordinalParse: /\d{1,2}(st|nd|rd|th)/,
ordinal : function (number) {
var b = number % 10,
output = (~~(number % 100 / 10) === 1) ? 'th' :
diff --git a/resources/lib/moment/locale/en-ca.js b/resources/lib/moment/locale/en-ca.js
index 077dc8b5..2dec8a61 100644
--- a/resources/lib/moment/locale/en-ca.js
+++ b/resources/lib/moment/locale/en-ca.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('en-ca', {
@@ -19,6 +19,7 @@
weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
longDateFormat : {
LT : 'h:mm A',
+ LTS : 'h:mm:ss A',
L : 'YYYY-MM-DD',
LL : 'D MMMM, YYYY',
LLL : 'D MMMM, YYYY LT',
@@ -47,6 +48,7 @@
y : 'a year',
yy : '%d years'
},
+ ordinalParse: /\d{1,2}(st|nd|rd|th)/,
ordinal : function (number) {
var b = number % 10,
output = (~~(number % 100 / 10) === 1) ? 'th' :
diff --git a/resources/lib/moment/locale/en-gb.js b/resources/lib/moment/locale/en-gb.js
index 4491d4a1..4ea2b29e 100644
--- a/resources/lib/moment/locale/en-gb.js
+++ b/resources/lib/moment/locale/en-gb.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('en-gb', {
@@ -19,6 +19,7 @@
weekdaysMin : 'Su_Mo_Tu_We_Th_Fr_Sa'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'HH:mm:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -47,6 +48,7 @@
y : 'a year',
yy : '%d years'
},
+ ordinalParse: /\d{1,2}(st|nd|rd|th)/,
ordinal : function (number) {
var b = number % 10,
output = (~~(number % 100 / 10) === 1) ? 'th' :
diff --git a/resources/lib/moment/locale/eo.js b/resources/lib/moment/locale/eo.js
index 735ed8ea..6a3d097b 100644
--- a/resources/lib/moment/locale/eo.js
+++ b/resources/lib/moment/locale/eo.js
@@ -10,7 +10,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('eo', {
@@ -21,6 +21,7 @@
weekdaysMin : 'Di_Lu_Ma_Me_Ĵa_Ve_Sa'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'YYYY-MM-DD',
LL : 'D[-an de] MMMM, YYYY',
LLL : 'D[-an de] MMMM, YYYY LT',
@@ -56,6 +57,7 @@
y : 'jaro',
yy : '%d jaroj'
},
+ ordinalParse: /\d{1,2}a/,
ordinal : '%da',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/es.js b/resources/lib/moment/locale/es.js
index 04b83a80..b6e30b10 100644
--- a/resources/lib/moment/locale/es.js
+++ b/resources/lib/moment/locale/es.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var monthsShortDot = 'ene._feb._mar._abr._may._jun._jul._ago._sep._oct._nov._dic.'.split('_'),
@@ -28,6 +28,7 @@
weekdaysMin : 'Do_Lu_Ma_Mi_Ju_Vi_Sá'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D [de] MMMM [de] YYYY',
LLL : 'D [de] MMMM [de] YYYY LT',
@@ -66,6 +67,7 @@
y : 'un año',
yy : '%d años'
},
+ ordinalParse : /\d{1,2}º/,
ordinal : '%dº',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/et.js b/resources/lib/moment/locale/et.js
index 242ee169..7dbcee72 100644
--- a/resources/lib/moment/locale/et.js
+++ b/resources/lib/moment/locale/et.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function processRelativeTime(number, withoutSuffix, key, isFuture) {
@@ -39,6 +39,7 @@
weekdaysMin : 'P_E_T_K_N_R_L'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY LT',
@@ -67,6 +68,7 @@
y : processRelativeTime,
yy : processRelativeTime
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/eu.js b/resources/lib/moment/locale/eu.js
index 8fb89b49..c455c466 100644
--- a/resources/lib/moment/locale/eu.js
+++ b/resources/lib/moment/locale/eu.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('eu', {
@@ -19,6 +19,7 @@
weekdaysMin : 'ig_al_ar_az_og_ol_lr'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'YYYY-MM-DD',
LL : 'YYYY[ko] MMMM[ren] D[a]',
LLL : 'YYYY[ko] MMMM[ren] D[a] LT',
@@ -51,6 +52,7 @@
y : 'urte bat',
yy : '%d urte'
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/fa.js b/resources/lib/moment/locale/fa.js
index b1151bdd..ad2087a2 100644
--- a/resources/lib/moment/locale/fa.js
+++ b/resources/lib/moment/locale/fa.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var symbolMap = {
@@ -43,6 +43,7 @@
weekdaysMin : 'ی_د_س_چ_پ_ج_ش'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -88,6 +89,7 @@
return symbolMap[match];
}).replace(/,/g, '،');
},
+ ordinalParse: /\d{1,2}م/,
ordinal : '%dم',
week : {
dow : 6, // Saturday is the first day of the week.
diff --git a/resources/lib/moment/locale/fi.js b/resources/lib/moment/locale/fi.js
index 1fedcaba..f884c3ef 100644
--- a/resources/lib/moment/locale/fi.js
+++ b/resources/lib/moment/locale/fi.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var numbersPast = 'nolla yksi kaksi kolme neljä viisi kuusi seitsemän kahdeksan yhdeksän'.split(' '),
@@ -64,6 +64,7 @@
weekdaysMin : 'su_ma_ti_ke_to_pe_la'.split('_'),
longDateFormat : {
LT : 'HH.mm',
+ LTS : 'HH.mm.ss',
L : 'DD.MM.YYYY',
LL : 'Do MMMM[ta] YYYY',
LLL : 'Do MMMM[ta] YYYY, [klo] LT',
@@ -96,6 +97,7 @@
y : translate,
yy : translate
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/fo.js b/resources/lib/moment/locale/fo.js
index a27f9da6..6b940e8e 100644
--- a/resources/lib/moment/locale/fo.js
+++ b/resources/lib/moment/locale/fo.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('fo', {
@@ -19,6 +19,7 @@
weekdaysMin : 'su_má_tý_mi_hó_fr_le'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -47,6 +48,7 @@
y : 'eitt ár',
yy : '%d ár'
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/fr-ca.js b/resources/lib/moment/locale/fr-ca.js
index c0f1bdc6..6cac1b84 100644
--- a/resources/lib/moment/locale/fr-ca.js
+++ b/resources/lib/moment/locale/fr-ca.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('fr-ca', {
@@ -19,6 +19,7 @@
weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'YYYY-MM-DD',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -47,6 +48,7 @@
y : 'un an',
yy : '%d ans'
},
+ ordinalParse: /\d{1,2}(er|)/,
ordinal : function (number) {
return number + (number === 1 ? 'er' : '');
}
diff --git a/resources/lib/moment/locale/fr.js b/resources/lib/moment/locale/fr.js
index f217ff1d..4a7cbcc5 100644
--- a/resources/lib/moment/locale/fr.js
+++ b/resources/lib/moment/locale/fr.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('fr', {
@@ -19,6 +19,7 @@
weekdaysMin : 'Di_Lu_Ma_Me_Je_Ve_Sa'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -47,6 +48,7 @@
y : 'un an',
yy : '%d ans'
},
+ ordinalParse: /\d{1,2}(er|)/,
ordinal : function (number) {
return number + (number === 1 ? 'er' : '');
},
diff --git a/resources/lib/moment/locale/gl.js b/resources/lib/moment/locale/gl.js
index ac638629..5ff9e3fe 100644
--- a/resources/lib/moment/locale/gl.js
+++ b/resources/lib/moment/locale/gl.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('gl', {
@@ -19,6 +19,7 @@
weekdaysMin : 'Do_Lu_Ma_Mé_Xo_Ve_Sá'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -62,6 +63,7 @@
y : 'un ano',
yy : '%d anos'
},
+ ordinalParse : /\d{1,2}º/,
ordinal : '%dº',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/he.js b/resources/lib/moment/locale/he.js
index 06f954f4..9f9f4705 100644
--- a/resources/lib/moment/locale/he.js
+++ b/resources/lib/moment/locale/he.js
@@ -10,7 +10,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('he', {
@@ -21,6 +21,7 @@
weekdaysMin : 'א_ב_ג_ד_ה_ו_ש'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D [ב]MMMM YYYY',
LLL : 'D [ב]MMMM YYYY LT',
diff --git a/resources/lib/moment/locale/hi.js b/resources/lib/moment/locale/hi.js
index 4e64560a..73deba5b 100644
--- a/resources/lib/moment/locale/hi.js
+++ b/resources/lib/moment/locale/hi.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var symbolMap = {
@@ -44,6 +44,7 @@
weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
longDateFormat : {
LT : 'A h:mm बजे',
+ LTS : 'A h:mm:ss बजे',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY, LT',
diff --git a/resources/lib/moment/locale/hr.js b/resources/lib/moment/locale/hr.js
index 9e3f6fa3..65264dc2 100644
--- a/resources/lib/moment/locale/hr.js
+++ b/resources/lib/moment/locale/hr.js
@@ -10,7 +10,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function translate(number, withoutSuffix, key) {
@@ -74,6 +74,7 @@
weekdaysMin : 'ne_po_ut_sr_če_pe_su'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'DD. MM. YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY LT',
@@ -130,6 +131,7 @@
y : 'godinu',
yy : translate
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/hu.js b/resources/lib/moment/locale/hu.js
index 73fdb83f..7eccd1d9 100644
--- a/resources/lib/moment/locale/hu.js
+++ b/resources/lib/moment/locale/hu.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var weekEndings = 'vasárnap hétfőn kedden szerdán csütörtökön pénteken szombaton'.split(' ');
@@ -57,6 +57,7 @@
weekdaysMin : 'v_h_k_sze_cs_p_szo'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'YYYY.MM.DD.',
LL : 'YYYY. MMMM D.',
LLL : 'YYYY. MMMM D., LT',
@@ -96,6 +97,7 @@
y : translate,
yy : translate
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/hy-am.js b/resources/lib/moment/locale/hy-am.js
index affcd7e8..053a845e 100644
--- a/resources/lib/moment/locale/hy-am.js
+++ b/resources/lib/moment/locale/hy-am.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function monthsCaseReplace(m, format) {
@@ -44,6 +44,7 @@
weekdaysMin : 'կրկ_երկ_երք_չրք_հնգ_ուրբ_շբթ'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D MMMM YYYY թ.',
LLL : 'D MMMM YYYY թ., LT',
@@ -89,6 +90,7 @@
}
},
+ ordinalParse: /\d{1,2}|\d{1,2}-(ին|րդ)/,
ordinal: function (number, period) {
switch (period) {
case 'DDD':
diff --git a/resources/lib/moment/locale/id.js b/resources/lib/moment/locale/id.js
index 143426aa..36a841a6 100644
--- a/resources/lib/moment/locale/id.js
+++ b/resources/lib/moment/locale/id.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('id', {
@@ -20,6 +20,7 @@
weekdaysMin : 'Mg_Sn_Sl_Rb_Km_Jm_Sb'.split('_'),
longDateFormat : {
LT : 'HH.mm',
+ LTS : 'LT.ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY [pukul] LT',
diff --git a/resources/lib/moment/locale/is.js b/resources/lib/moment/locale/is.js
index 479f82d9..21888aa2 100644
--- a/resources/lib/moment/locale/is.js
+++ b/resources/lib/moment/locale/is.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function plural(n) {
@@ -87,6 +87,7 @@
weekdaysMin : 'Su_Má_Þr_Mi_Fi_Fö_La'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY [kl.] LT',
@@ -115,6 +116,7 @@
y : translate,
yy : translate
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/it.js b/resources/lib/moment/locale/it.js
index 66953909..9d14714f 100644
--- a/resources/lib/moment/locale/it.js
+++ b/resources/lib/moment/locale/it.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('it', {
@@ -20,6 +20,7 @@
weekdaysMin : 'D_L_Ma_Me_G_V_S'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -30,7 +31,14 @@
nextDay: '[Domani alle] LT',
nextWeek: 'dddd [alle] LT',
lastDay: '[Ieri alle] LT',
- lastWeek: '[lo scorso] dddd [alle] LT',
+ lastWeek: function () {
+ switch (this.day()) {
+ case 0:
+ return '[la scorsa] dddd [alle] LT';
+ default:
+ return '[lo scorso] dddd [alle] LT';
+ }
+ },
sameElse: 'L'
},
relativeTime : {
@@ -50,6 +58,7 @@
y : 'un anno',
yy : '%d anni'
},
+ ordinalParse : /\d{1,2}º/,
ordinal: '%dº',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/ja.js b/resources/lib/moment/locale/ja.js
index f14fa4e6..3f55bcfd 100644
--- a/resources/lib/moment/locale/ja.js
+++ b/resources/lib/moment/locale/ja.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('ja', {
@@ -19,6 +19,7 @@
weekdaysMin : '日_月_火_水_木_金_土'.split('_'),
longDateFormat : {
LT : 'Ah時m分',
+ LTS : 'LTs秒',
L : 'YYYY/MM/DD',
LL : 'YYYY年M月D日',
LLL : 'YYYY年M月D日LT',
diff --git a/resources/lib/moment/locale/ka.js b/resources/lib/moment/locale/ka.js
index 73eb9c75..b56e18cb 100644
--- a/resources/lib/moment/locale/ka.js
+++ b/resources/lib/moment/locale/ka.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function monthsCaseReplace(m, format) {
@@ -45,6 +45,7 @@
weekdaysMin : 'კვ_ორ_სა_ოთ_ხუ_პა_შა'.split('_'),
longDateFormat : {
LT : 'h:mm A',
+ LTS : 'h:mm:ss A',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -84,6 +85,7 @@
y : 'წელი',
yy : '%d წელი'
},
+ ordinalParse: /0|1-ლი|მე-\d{1,2}|\d{1,2}-ე/,
ordinal : function (number) {
if (number === 0) {
return number;
diff --git a/resources/lib/moment/locale/km.js b/resources/lib/moment/locale/km.js
index 9ba4888b..8d7b9b85 100644
--- a/resources/lib/moment/locale/km.js
+++ b/resources/lib/moment/locale/km.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('km', {
@@ -19,6 +19,7 @@
weekdaysMin: 'អាទិត្យ_ច័ន្ទ_អង្គារ_ពុធ_ព្រហស្បតិ៍_សុក្រ_សៅរ៍'.split('_'),
longDateFormat: {
LT: 'HH:mm',
+ LTS : 'LT:ss',
L: 'DD/MM/YYYY',
LL: 'D MMMM YYYY',
LLL: 'D MMMM YYYY LT',
diff --git a/resources/lib/moment/locale/ko.js b/resources/lib/moment/locale/ko.js
index 57017f5e..956345bd 100644
--- a/resources/lib/moment/locale/ko.js
+++ b/resources/lib/moment/locale/ko.js
@@ -11,7 +11,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('ko', {
@@ -22,6 +22,7 @@
weekdaysMin : '일_월_화_수_목_금_토'.split('_'),
longDateFormat : {
LT : 'A h시 m분',
+ LTS : 'A h시 m분 s초',
L : 'YYYY.MM.DD',
LL : 'YYYY년 MMMM D일',
LLL : 'YYYY년 MMMM D일 LT',
@@ -54,6 +55,7 @@
y : '일년',
yy : '%d년'
},
+ ordinalParse : /\d{1,2}일/,
ordinal : '%d일',
meridiemParse : /(오전|오후)/,
isPM : function (token) {
diff --git a/resources/lib/moment/locale/lb.js b/resources/lib/moment/locale/lb.js
index 14fab973..2e84dab3 100644
--- a/resources/lib/moment/locale/lb.js
+++ b/resources/lib/moment/locale/lb.js
@@ -12,7 +12,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function processRelativeTime(number, withoutSuffix, key, isFuture) {
@@ -91,6 +91,7 @@
weekdaysMin: 'So_Mé_Dë_Më_Do_Fr_Sa'.split('_'),
longDateFormat: {
LT: 'H:mm [Auer]',
+ LTS: 'H:mm:ss [Auer]',
L: 'DD.MM.YYYY',
LL: 'D. MMMM YYYY',
LLL: 'D. MMMM YYYY LT',
@@ -128,6 +129,7 @@
y : processRelativeTime,
yy : '%d Joer'
},
+ ordinalParse: /\d{1,2}\./,
ordinal: '%d.',
week: {
dow: 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/lt.js b/resources/lib/moment/locale/lt.js
index 013f8f1e..2d87e04c 100644
--- a/resources/lib/moment/locale/lt.js
+++ b/resources/lib/moment/locale/lt.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var units = {
@@ -75,6 +75,7 @@
weekdaysMin : 'S_P_A_T_K_Pn_Š'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'YYYY-MM-DD',
LL : 'YYYY [m.] MMMM D [d.]',
LLL : 'YYYY [m.] MMMM D [d.], LT [val.]',
@@ -107,6 +108,7 @@
y : translateSingular,
yy : translate
},
+ ordinalParse: /\d{1,2}-oji/,
ordinal : function (number) {
return number + '-oji';
},
diff --git a/resources/lib/moment/locale/lv.js b/resources/lib/moment/locale/lv.js
index 7e1892e3..47a0708c 100644
--- a/resources/lib/moment/locale/lv.js
+++ b/resources/lib/moment/locale/lv.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var units = {
@@ -40,6 +40,7 @@
weekdaysMin : 'Sv_P_O_T_C_Pk_S'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'YYYY. [gada] D. MMMM',
LLL : 'YYYY. [gada] D. MMMM, LT',
@@ -68,6 +69,7 @@
y : 'gadu',
yy : relativeTimeWithPlural
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/mk.js b/resources/lib/moment/locale/mk.js
index 94c7fc1a..de366319 100644
--- a/resources/lib/moment/locale/mk.js
+++ b/resources/lib/moment/locale/mk.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('mk', {
@@ -19,6 +19,7 @@
weekdaysMin : 'нe_пo_вт_ср_че_пе_сa'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'D.MM.YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -59,6 +60,7 @@
y : 'година',
yy : '%d години'
},
+ ordinalParse: /\d{1,2}-(ев|ен|ти|ви|ри|ми)/,
ordinal : function (number) {
var lastDigit = number % 10,
last2Digits = number % 100;
diff --git a/resources/lib/moment/locale/ml.js b/resources/lib/moment/locale/ml.js
index ea4d9490..38509141 100644
--- a/resources/lib/moment/locale/ml.js
+++ b/resources/lib/moment/locale/ml.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('ml', {
@@ -19,6 +19,7 @@
weekdaysMin : 'ഞാ_തി_ചൊ_ബു_വ്യാ_വെ_ശ'.split('_'),
longDateFormat : {
LT : 'A h:mm -നു',
+ LTS : 'A h:mm:ss -നു',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY, LT',
diff --git a/resources/lib/moment/locale/mr.js b/resources/lib/moment/locale/mr.js
index 141eaf86..45c200e8 100644
--- a/resources/lib/moment/locale/mr.js
+++ b/resources/lib/moment/locale/mr.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var symbolMap = {
@@ -44,6 +44,7 @@
weekdaysMin : 'र_सो_मं_बु_गु_शु_श'.split('_'),
longDateFormat : {
LT : 'A h:mm वाजता',
+ LTS : 'A h:mm:ss वाजता',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY, LT',
diff --git a/resources/lib/moment/locale/ms-my.js b/resources/lib/moment/locale/ms-my.js
index 7efcbaaa..09ec280b 100644
--- a/resources/lib/moment/locale/ms-my.js
+++ b/resources/lib/moment/locale/ms-my.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('ms-my', {
@@ -19,6 +19,7 @@
weekdaysMin : 'Ah_Is_Sl_Rb_Km_Jm_Sb'.split('_'),
longDateFormat : {
LT : 'HH.mm',
+ LTS : 'LT.ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY [pukul] LT',
diff --git a/resources/lib/moment/locale/my.js b/resources/lib/moment/locale/my.js
index 138d1014..31f5c9ea 100644
--- a/resources/lib/moment/locale/my.js
+++ b/resources/lib/moment/locale/my.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var symbolMap = {
@@ -42,6 +42,7 @@
weekdaysMin: 'နွေ_လာ_င်္ဂါ_ဟူး_ကြာ_သော_နေ'.split('_'),
longDateFormat: {
LT: 'HH:mm',
+ LTS: 'HH:mm:ss',
L: 'DD/MM/YYYY',
LL: 'D MMMM YYYY',
LLL: 'D MMMM YYYY LT',
diff --git a/resources/lib/moment/locale/nb.js b/resources/lib/moment/locale/nb.js
index 533659d5..4764b505 100644
--- a/resources/lib/moment/locale/nb.js
+++ b/resources/lib/moment/locale/nb.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('nb', {
@@ -20,6 +20,7 @@
weekdaysMin : 'sø_ma_ti_on_to_fr_lø'.split('_'),
longDateFormat : {
LT : 'H.mm',
+ LTS : 'LT.ss',
L : 'DD.MM.YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY [kl.] LT',
@@ -48,6 +49,7 @@
y : 'ett år',
yy : '%d år'
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/ne.js b/resources/lib/moment/locale/ne.js
index 51629ebd..ceb28341 100644
--- a/resources/lib/moment/locale/ne.js
+++ b/resources/lib/moment/locale/ne.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var symbolMap = {
@@ -44,6 +44,7 @@
weekdaysMin : 'आइ._सो._मङ्_बु._बि._शु._श.'.split('_'),
longDateFormat : {
LT : 'Aको h:mm बजे',
+ LTS : 'Aको h:mm:ss बजे',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY, LT',
diff --git a/resources/lib/moment/locale/nl.js b/resources/lib/moment/locale/nl.js
index 213beeb8..9f4fdfe7 100644
--- a/resources/lib/moment/locale/nl.js
+++ b/resources/lib/moment/locale/nl.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var monthsShortWithDots = 'jan._feb._mrt._apr._mei_jun._jul._aug._sep._okt._nov._dec.'.split('_'),
@@ -28,6 +28,7 @@
weekdaysMin : 'Zo_Ma_Di_Wo_Do_Vr_Za'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD-MM-YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -56,6 +57,7 @@
y : 'één jaar',
yy : '%d jaar'
},
+ ordinalParse: /\d{1,2}(ste|de)/,
ordinal : function (number) {
return number + ((number === 1 || number === 8 || number >= 20) ? 'ste' : 'de');
},
diff --git a/resources/lib/moment/locale/nn.js b/resources/lib/moment/locale/nn.js
index c5b65055..d7a82380 100644
--- a/resources/lib/moment/locale/nn.js
+++ b/resources/lib/moment/locale/nn.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('nn', {
@@ -19,6 +19,7 @@
weekdaysMin : 'su_må_ty_on_to_fr_lø'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -47,6 +48,7 @@
y : 'eit år',
yy : '%d år'
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/pl.js b/resources/lib/moment/locale/pl.js
index 63a62f13..418ca817 100644
--- a/resources/lib/moment/locale/pl.js
+++ b/resources/lib/moment/locale/pl.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var monthsNominative = 'styczeń_luty_marzec_kwiecień_maj_czerwiec_lipiec_sierpień_wrzesień_październik_listopad_grudzień'.split('_'),
@@ -50,6 +50,7 @@
weekdaysMin : 'N_Pn_Wt_Śr_Cz_Pt_So'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -89,6 +90,7 @@
y : 'rok',
yy : translate
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/pt-br.js b/resources/lib/moment/locale/pt-br.js
index 44eedaf0..813c2de4 100644
--- a/resources/lib/moment/locale/pt-br.js
+++ b/resources/lib/moment/locale/pt-br.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('pt-br', {
@@ -19,6 +19,7 @@
weekdaysMin : 'dom_2ª_3ª_4ª_5ª_6ª_sáb'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D [de] MMMM [de] YYYY',
LLL : 'D [de] MMMM [de] YYYY [às] LT',
@@ -51,6 +52,7 @@
y : 'um ano',
yy : '%d anos'
},
+ ordinalParse: /\d{1,2}º/,
ordinal : '%dº'
});
}));
diff --git a/resources/lib/moment/locale/pt.js b/resources/lib/moment/locale/pt.js
index aced692e..4afd5643 100644
--- a/resources/lib/moment/locale/pt.js
+++ b/resources/lib/moment/locale/pt.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('pt', {
@@ -19,6 +19,7 @@
weekdaysMin : 'dom_2ª_3ª_4ª_5ª_6ª_sáb'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D [de] MMMM [de] YYYY',
LLL : 'D [de] MMMM [de] YYYY LT',
@@ -51,6 +52,7 @@
y : 'um ano',
yy : '%d anos'
},
+ ordinalParse: /\d{1,2}º/,
ordinal : '%dº',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/ro.js b/resources/lib/moment/locale/ro.js
index dc34d3c3..fcc7d07d 100644
--- a/resources/lib/moment/locale/ro.js
+++ b/resources/lib/moment/locale/ro.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function relativeTimeWithPlural(number, withoutSuffix, key) {
@@ -36,6 +36,7 @@
weekdaysMin : 'Du_Lu_Ma_Mi_Jo_Vi_Sâ'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY H:mm',
diff --git a/resources/lib/moment/locale/ru.js b/resources/lib/moment/locale/ru.js
index 2f15233b..5adfa9ac 100644
--- a/resources/lib/moment/locale/ru.js
+++ b/resources/lib/moment/locale/ru.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function plural(word, num) {
@@ -48,7 +48,7 @@
function monthsShortCaseReplace(m, format) {
var monthsShort = {
- 'nominative': 'янв_фев_мар_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'),
+ 'nominative': 'янв_фев_март_апр_май_июнь_июль_авг_сен_окт_ноя_дек'.split('_'),
'accusative': 'янв_фев_мар_апр_мая_июня_июля_авг_сен_окт_ноя_дек'.split('_')
},
@@ -65,7 +65,7 @@
'accusative': 'воскресенье_понедельник_вторник_среду_четверг_пятницу_субботу'.split('_')
},
- nounCase = (/\[ ?[Вв] ?(?:прошлую|следующую)? ?\] ?dddd/).test(format) ?
+ nounCase = (/\[ ?[Вв] ?(?:прошлую|следующую|эту)? ?\] ?dddd/).test(format) ?
'accusative' :
'nominative';
@@ -81,6 +81,7 @@
monthsParse : [/^янв/i, /^фев/i, /^мар/i, /^апр/i, /^ма[й|я]/i, /^июн/i, /^июл/i, /^авг/i, /^сен/i, /^окт/i, /^ноя/i, /^дек/i],
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D MMMM YYYY г.',
LLL : 'D MMMM YYYY г., LT',
@@ -93,18 +94,26 @@
nextWeek: function () {
return this.day() === 2 ? '[Во] dddd [в] LT' : '[В] dddd [в] LT';
},
- lastWeek: function () {
- switch (this.day()) {
- case 0:
- return '[В прошлое] dddd [в] LT';
- case 1:
- case 2:
- case 4:
- return '[В прошлый] dddd [в] LT';
- case 3:
- case 5:
- case 6:
- return '[В прошлую] dddd [в] LT';
+ lastWeek: function (now) {
+ if (now.week() !== this.week()) {
+ switch (this.day()) {
+ case 0:
+ return '[В прошлое] dddd [в] LT';
+ case 1:
+ case 2:
+ case 4:
+ return '[В прошлый] dddd [в] LT';
+ case 3:
+ case 5:
+ case 6:
+ return '[В прошлую] dddd [в] LT';
+ }
+ } else {
+ if (this.day() === 2) {
+ return '[Во] dddd [в] LT';
+ } else {
+ return '[В] dddd [в] LT';
+ }
}
},
sameElse: 'L'
@@ -142,6 +151,7 @@
}
},
+ ordinalParse: /\d{1,2}-(й|го|я)/,
ordinal: function (number, period) {
switch (period) {
case 'M':
diff --git a/resources/lib/moment/locale/sk.js b/resources/lib/moment/locale/sk.js
index 991afebb..f9d74c5d 100644
--- a/resources/lib/moment/locale/sk.js
+++ b/resources/lib/moment/locale/sk.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var months = 'január_február_marec_apríl_máj_jún_júl_august_september_október_november_december'.split('_'),
@@ -88,6 +88,7 @@
weekdaysMin : 'ne_po_ut_st_št_pi_so'.split('_'),
longDateFormat : {
LT: 'H:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY LT',
@@ -147,6 +148,7 @@
y : translate,
yy : translate
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/sl.js b/resources/lib/moment/locale/sl.js
index 2bdbf1cd..232695fa 100644
--- a/resources/lib/moment/locale/sl.js
+++ b/resources/lib/moment/locale/sl.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function translate(number, withoutSuffix, key) {
@@ -80,6 +80,7 @@
weekdaysMin : 'ne_po_to_sr_če_pe_so'.split('_'),
longDateFormat : {
LT : 'H:mm',
+ LTS : 'LT:ss',
L : 'DD. MM. YYYY',
LL : 'D. MMMM YYYY',
LLL : 'D. MMMM YYYY LT',
@@ -135,6 +136,7 @@
y : 'eno leto',
yy : translate
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/sq.js b/resources/lib/moment/locale/sq.js
index 6ae41787..415495aa 100644
--- a/resources/lib/moment/locale/sq.js
+++ b/resources/lib/moment/locale/sq.js
@@ -10,7 +10,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('sq', {
@@ -24,6 +24,7 @@
},
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -52,6 +53,7 @@
y : 'një vit',
yy : '%d vite'
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/sr-cyrl.js b/resources/lib/moment/locale/sr-cyrl.js
index 7278de6e..57619b64 100644
--- a/resources/lib/moment/locale/sr-cyrl.js
+++ b/resources/lib/moment/locale/sr-cyrl.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var translator = {
@@ -42,6 +42,7 @@
weekdaysMin: ['не', 'по', 'ут', 'ср', 'че', 'пе', 'су'],
longDateFormat: {
LT: 'H:mm',
+ LTS : 'LT:ss',
L: 'DD. MM. YYYY',
LL: 'D. MMMM YYYY',
LLL: 'D. MMMM YYYY LT',
@@ -96,6 +97,7 @@
y : 'годину',
yy : translator.translate
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/sr.js b/resources/lib/moment/locale/sr.js
index d008282e..6f142843 100644
--- a/resources/lib/moment/locale/sr.js
+++ b/resources/lib/moment/locale/sr.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var translator = {
@@ -42,6 +42,7 @@
weekdaysMin: ['ne', 'po', 'ut', 'sr', 'če', 'pe', 'su'],
longDateFormat: {
LT: 'H:mm',
+ LTS : 'LT:ss',
L: 'DD. MM. YYYY',
LL: 'D. MMMM YYYY',
LLL: 'D. MMMM YYYY LT',
@@ -96,6 +97,7 @@
y : 'godinu',
yy : translator.translate
},
+ ordinalParse: /\d{1,2}\./,
ordinal : '%d.',
week : {
dow : 1, // Monday is the first day of the week.
diff --git a/resources/lib/moment/locale/sv.js b/resources/lib/moment/locale/sv.js
index 634b3cfe..6e149580 100644
--- a/resources/lib/moment/locale/sv.js
+++ b/resources/lib/moment/locale/sv.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('sv', {
@@ -19,6 +19,7 @@
weekdaysMin : 'sö_må_ti_on_to_fr_lö'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'YYYY-MM-DD',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -47,6 +48,7 @@
y : 'ett år',
yy : '%d år'
},
+ ordinalParse: /\d{1,2}(e|a)/,
ordinal : function (number) {
var b = number % 10,
output = (~~(number % 100 / 10) === 1) ? 'e' :
diff --git a/resources/lib/moment/locale/ta.js b/resources/lib/moment/locale/ta.js
index 53bab0d9..d0356a3e 100644
--- a/resources/lib/moment/locale/ta.js
+++ b/resources/lib/moment/locale/ta.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
/*var symbolMap = {
@@ -44,6 +44,7 @@
weekdaysMin : 'ஞா_தி_செ_பு_வி_வெ_ச'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY, LT',
@@ -82,6 +83,7 @@
return symbolMap[match];
});
},*/
+ ordinalParse: /\d{1,2}வது/,
ordinal : function (number) {
return number + 'வது';
},
diff --git a/resources/lib/moment/locale/th.js b/resources/lib/moment/locale/th.js
index fc99701d..e3c54229 100644
--- a/resources/lib/moment/locale/th.js
+++ b/resources/lib/moment/locale/th.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('th', {
@@ -19,6 +19,7 @@
weekdaysMin : 'อา._จ._อ._พ._พฤ._ศ._ส.'.split('_'),
longDateFormat : {
LT : 'H นาฬิกา m นาที',
+ LTS : 'LT s วินาที',
L : 'YYYY/MM/DD',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY เวลา LT',
diff --git a/resources/lib/moment/locale/tl-ph.js b/resources/lib/moment/locale/tl-ph.js
index c15cc1f0..40dbb075 100644
--- a/resources/lib/moment/locale/tl-ph.js
+++ b/resources/lib/moment/locale/tl-ph.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('tl-ph', {
@@ -19,6 +19,7 @@
weekdaysMin : 'Li_Lu_Ma_Mi_Hu_Bi_Sab'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'MM/D/YYYY',
LL : 'MMMM D, YYYY',
LLL : 'MMMM D, YYYY LT',
@@ -47,6 +48,7 @@
y : 'isang taon',
yy : '%d taon'
},
+ ordinalParse: /\d{1,2}/,
ordinal : function (number) {
return number;
},
diff --git a/resources/lib/moment/locale/tr.js b/resources/lib/moment/locale/tr.js
index 36e8fca1..cd0a7462 100644
--- a/resources/lib/moment/locale/tr.js
+++ b/resources/lib/moment/locale/tr.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
var suffixes = {
@@ -46,6 +46,7 @@
weekdaysMin : 'Pz_Pt_Sa_Ça_Pe_Cu_Ct'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
@@ -74,6 +75,7 @@
y : 'bir yıl',
yy : '%d yıl'
},
+ ordinalParse: /\d{1,2}'(inci|nci|üncü|ncı|uncu|ıncı)/,
ordinal : function (number) {
if (number === 0) { // special case for zero
return number + '\'ıncı';
diff --git a/resources/lib/moment/locale/tzm-latn.js b/resources/lib/moment/locale/tzm-latn.js
index 31897725..34592b45 100644
--- a/resources/lib/moment/locale/tzm-latn.js
+++ b/resources/lib/moment/locale/tzm-latn.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('tzm-latn', {
@@ -19,6 +19,7 @@
weekdaysMin : 'asamas_aynas_asinas_akras_akwas_asimwas_asiḍyas'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
diff --git a/resources/lib/moment/locale/tzm.js b/resources/lib/moment/locale/tzm.js
index 0a7f3f1e..95915212 100644
--- a/resources/lib/moment/locale/tzm.js
+++ b/resources/lib/moment/locale/tzm.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('tzm', {
@@ -19,6 +19,7 @@
weekdaysMin : 'ⴰⵙⴰⵎⴰⵙ_ⴰⵢⵏⴰⵙ_ⴰⵙⵉⵏⴰⵙ_ⴰⴽⵔⴰⵙ_ⴰⴽⵡⴰⵙ_ⴰⵙⵉⵎⵡⴰⵙ_ⴰⵙⵉⴹⵢⴰⵙ'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS: 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
diff --git a/resources/lib/moment/locale/uk.js b/resources/lib/moment/locale/uk.js
index bc22fff9..3dce4bca 100644
--- a/resources/lib/moment/locale/uk.js
+++ b/resources/lib/moment/locale/uk.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
function plural(word, num) {
@@ -79,6 +79,7 @@
weekdaysMin : 'нд_пн_вт_ср_чт_пт_сб'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD.MM.YYYY',
LL : 'D MMMM YYYY р.',
LLL : 'D MMMM YYYY р., LT',
@@ -134,6 +135,7 @@
}
},
+ ordinalParse: /\d{1,2}-(й|го)/,
ordinal: function (number, period) {
switch (period) {
case 'M':
diff --git a/resources/lib/moment/locale/uz.js b/resources/lib/moment/locale/uz.js
index 62fb89e0..139e4deb 100644
--- a/resources/lib/moment/locale/uz.js
+++ b/resources/lib/moment/locale/uz.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('uz', {
@@ -19,6 +19,7 @@
weekdaysMin : 'Як_Ду_Се_Чо_Па_Жу_Ша'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM YYYY',
LLL : 'D MMMM YYYY LT',
diff --git a/resources/lib/moment/locale/vi.js b/resources/lib/moment/locale/vi.js
index 20e3ffe2..15ec7dda 100644
--- a/resources/lib/moment/locale/vi.js
+++ b/resources/lib/moment/locale/vi.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('vi', {
@@ -19,6 +19,7 @@
weekdaysMin : 'CN_T2_T3_T4_T5_T6_T7'.split('_'),
longDateFormat : {
LT : 'HH:mm',
+ LTS : 'LT:ss',
L : 'DD/MM/YYYY',
LL : 'D MMMM [năm] YYYY',
LLL : 'D MMMM [năm] YYYY LT',
@@ -51,6 +52,7 @@
y : 'một năm',
yy : '%d năm'
},
+ ordinalParse: /\d{1,2}/,
ordinal : function (number) {
return number;
},
diff --git a/resources/lib/moment/locale/zh-cn.js b/resources/lib/moment/locale/zh-cn.js
index aff26c5e..b8a0bd2e 100644
--- a/resources/lib/moment/locale/zh-cn.js
+++ b/resources/lib/moment/locale/zh-cn.js
@@ -9,7 +9,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('zh-cn', {
@@ -20,6 +20,7 @@
weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
longDateFormat : {
LT : 'Ah点mm',
+ LTS : 'Ah点m分s秒',
L : 'YYYY-MM-DD',
LL : 'YYYY年MMMD日',
LLL : 'YYYY年MMMD日LT',
@@ -69,6 +70,7 @@
},
sameElse : 'LL'
},
+ ordinalParse: /\d{1,2}(日|月|周)/,
ordinal : function (number, period) {
switch (period) {
case 'd':
diff --git a/resources/lib/moment/locale/zh-tw.js b/resources/lib/moment/locale/zh-tw.js
index 71f99a26..b3c4439c 100644
--- a/resources/lib/moment/locale/zh-tw.js
+++ b/resources/lib/moment/locale/zh-tw.js
@@ -8,7 +8,7 @@
} else if (typeof exports === 'object') {
module.exports = factory(require('../moment')); // Node
} else {
- factory(window.moment); // Browser global
+ factory((typeof global !== 'undefined' ? global : this).moment); // node or other global
}
}(function (moment) {
return moment.defineLocale('zh-tw', {
@@ -19,6 +19,7 @@
weekdaysMin : '日_一_二_三_四_五_六'.split('_'),
longDateFormat : {
LT : 'Ah點mm',
+ LTS : 'Ah點m分s秒',
L : 'YYYY年MMMD日',
LL : 'YYYY年MMMD日',
LLL : 'YYYY年MMMD日LT',
@@ -50,6 +51,7 @@
lastWeek : '[上]ddddLT',
sameElse : 'L'
},
+ ordinalParse: /\d{1,2}(日|月|週)/,
ordinal : function (number, period) {
switch (period) {
case 'd' :
diff --git a/resources/lib/moment/moment.js b/resources/lib/moment/moment.js
index d100a9c4..85e190d4 100644
--- a/resources/lib/moment/moment.js
+++ b/resources/lib/moment/moment.js
@@ -1,5 +1,5 @@
//! moment.js
-//! version : 2.8.3
+//! version : 2.8.4
//! authors : Tim Wood, Iskren Chernev, Moment.js contributors
//! license : MIT
//! momentjs.com
@@ -10,7 +10,7 @@
************************************/
var moment,
- VERSION = '2.8.3',
+ VERSION = '2.8.4',
// the global-scope this is NOT the global object in Node.js
globalScope = typeof global !== 'undefined' ? global : this,
oldGlobalMoment,
@@ -33,7 +33,7 @@
momentProperties = [],
// check for nodeJS
- hasModule = (typeof module !== 'undefined' && module.exports),
+ hasModule = (typeof module !== 'undefined' && module && module.exports),
// ASP.NET json date format regex
aspNetJsonRegex = /^\/?Date\((\-?\d+)/i,
@@ -44,8 +44,8 @@
isoDurationRegex = /^(-)?P(?:(?:([0-9,.]*)Y)?(?:([0-9,.]*)M)?(?:([0-9,.]*)D)?(?:T(?:([0-9,.]*)H)?(?:([0-9,.]*)M)?(?:([0-9,.]*)S)?)?|([0-9,.]*)W)$/,
// format tokens
- formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|X|zz?|ZZ?|.)/g,
- localFormattingTokens = /(\[[^\[]*\])|(\\)?(LT|LL?L?L?|l{1,4})/g,
+ formattingTokens = /(\[[^\[]*\])|(\\)?(Mo|MM?M?M?|Do|DDDo|DD?D?D?|ddd?d?|do?|w[o|w]?|W[o|W]?|Q|YYYYYY|YYYYY|YYYY|YY|gg(ggg?)?|GG(GGG?)?|e|E|a|A|hh?|HH?|mm?|ss?|S{1,4}|x|X|zz?|ZZ?|.)/g,
+ localFormattingTokens = /(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,
// parsing token regexes
parseTokenOneOrTwoDigits = /\d\d?/, // 0 - 99
@@ -56,8 +56,8 @@
parseTokenWord = /[0-9]*['a-z\u00A0-\u05FF\u0700-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]+|[\u0600-\u06FF\/]+(\s*?[\u0600-\u06FF]+){1,2}/i, // any word (or two) characters or numbers including two/three word month in arabic.
parseTokenTimezone = /Z|[\+\-]\d\d:?\d\d/gi, // +00:00 -00:00 +0000 -0000 or Z
parseTokenT = /T/i, // T (ISO separator)
+ parseTokenOffsetMs = /[\+\-]?\d+/, // 1234567890123
parseTokenTimestampMs = /[\+\-]?\d+(\.\d{1,3})?/, // 123456789 123456789.123
- parseTokenOrdinal = /\d{1,2}/,
//strict parsing regexes
parseTokenOneDigit = /\d/, // 0 - 9
@@ -272,6 +272,9 @@
zz : function () {
return this.zoneName();
},
+ x : function () {
+ return this.valueOf();
+ },
X : function () {
return this.unix();
},
@@ -698,7 +701,10 @@
overflow =
m._a[MONTH] < 0 || m._a[MONTH] > 11 ? MONTH :
m._a[DATE] < 1 || m._a[DATE] > daysInMonth(m._a[YEAR], m._a[MONTH]) ? DATE :
- m._a[HOUR] < 0 || m._a[HOUR] > 23 ? HOUR :
+ m._a[HOUR] < 0 || m._a[HOUR] > 24 ||
+ (m._a[HOUR] === 24 && (m._a[MINUTE] !== 0 ||
+ m._a[SECOND] !== 0 ||
+ m._a[MILLISECOND] !== 0)) ? HOUR :
m._a[MINUTE] < 0 || m._a[MINUTE] > 59 ? MINUTE :
m._a[SECOND] < 0 || m._a[SECOND] > 59 ? SECOND :
m._a[MILLISECOND] < 0 || m._a[MILLISECOND] > 999 ? MILLISECOND :
@@ -725,7 +731,8 @@
if (m._strict) {
m._isValid = m._isValid &&
m._pf.charsLeftOver === 0 &&
- m._pf.unusedTokens.length === 0;
+ m._pf.unusedTokens.length === 0 &&
+ m._pf.bigHour === undefined;
}
}
return m._isValid;
@@ -777,8 +784,18 @@
// Return a moment from input, that is local/utc/zone equivalent to model.
function makeAs(input, model) {
- return model._isUTC ? moment(input).zone(model._offset || 0) :
- moment(input).local();
+ var res, diff;
+ if (model._isUTC) {
+ res = model.clone();
+ diff = (moment.isMoment(input) || isDate(input) ?
+ +input : +moment(input)) - (+res);
+ // Use low-level api, because this fn is low-level api.
+ res._d.setTime(+res._d + diff);
+ moment.updateOffset(res, false);
+ return res;
+ } else {
+ return moment(input).local();
+ }
}
/************************************
@@ -798,6 +815,9 @@
this['_' + i] = prop;
}
}
+ // Lenient ordinal parsing accepts just a number in addition to
+ // number + (possibly) stuff coming from _ordinalParseLenient.
+ this._ordinalParseLenient = new RegExp(this._ordinalParse.source + '|' + /\d{1,2}/.source);
},
_months : 'January_February_March_April_May_June_July_August_September_October_November_December'.split('_'),
@@ -810,22 +830,32 @@
return this._monthsShort[m.month()];
},
- monthsParse : function (monthName) {
+ monthsParse : function (monthName, format, strict) {
var i, mom, regex;
if (!this._monthsParse) {
this._monthsParse = [];
+ this._longMonthsParse = [];
+ this._shortMonthsParse = [];
}
for (i = 0; i < 12; i++) {
// make the regex if we don't have it already
- if (!this._monthsParse[i]) {
- mom = moment.utc([2000, i]);
+ mom = moment.utc([2000, i]);
+ if (strict && !this._longMonthsParse[i]) {
+ this._longMonthsParse[i] = new RegExp('^' + this.months(mom, '').replace('.', '') + '$', 'i');
+ this._shortMonthsParse[i] = new RegExp('^' + this.monthsShort(mom, '').replace('.', '') + '$', 'i');
+ }
+ if (!strict && !this._monthsParse[i]) {
regex = '^' + this.months(mom, '') + '|^' + this.monthsShort(mom, '');
this._monthsParse[i] = new RegExp(regex.replace('.', ''), 'i');
}
// test the regex
- if (this._monthsParse[i].test(monthName)) {
+ if (strict && format === 'MMMM' && this._longMonthsParse[i].test(monthName)) {
+ return i;
+ } else if (strict && format === 'MMM' && this._shortMonthsParse[i].test(monthName)) {
+ return i;
+ } else if (!strict && this._monthsParse[i].test(monthName)) {
return i;
}
}
@@ -868,6 +898,7 @@
},
_longDateFormat : {
+ LTS : 'h:mm:ss A',
LT : 'h:mm A',
L : 'MM/DD/YYYY',
LL : 'MMMM D, YYYY',
@@ -908,9 +939,9 @@
lastWeek : '[Last] dddd [at] LT',
sameElse : 'L'
},
- calendar : function (key, mom) {
+ calendar : function (key, mom, now) {
var output = this._calendar[key];
- return typeof output === 'function' ? output.apply(mom) : output;
+ return typeof output === 'function' ? output.apply(mom, [now]) : output;
},
_relativeTime : {
@@ -945,6 +976,7 @@
return this._ordinal.replace('%d', number);
},
_ordinal : '%d',
+ _ordinalParse : /\d{1,2}/,
preparse : function (string) {
return string;
@@ -1086,6 +1118,8 @@
case 'a':
case 'A':
return config._locale._meridiemParse;
+ case 'x':
+ return parseTokenOffsetMs;
case 'X':
return parseTokenTimestampMs;
case 'Z':
@@ -1120,7 +1154,7 @@
case 'E':
return parseTokenOneOrTwoDigits;
case 'Do':
- return parseTokenOrdinal;
+ return strict ? config._locale._ordinalParse : config._locale._ordinalParseLenient;
default :
a = new RegExp(regexpEscape(unescapeFormat(token.replace('\\', '')), 'i'));
return a;
@@ -1157,7 +1191,7 @@
break;
case 'MMM' : // fall through to MMMM
case 'MMMM' :
- a = config._locale.monthsParse(input);
+ a = config._locale.monthsParse(input, token, config._strict);
// if we didn't find a month name, mark the date as invalid.
if (a != null) {
datePartArray[MONTH] = a;
@@ -1174,7 +1208,8 @@
break;
case 'Do' :
if (input != null) {
- datePartArray[DATE] = toInt(parseInt(input, 10));
+ datePartArray[DATE] = toInt(parseInt(
+ input.match(/\d{1,2}/)[0], 10));
}
break;
// DAY OF YEAR
@@ -1199,11 +1234,13 @@
case 'A' :
config._isPm = config._locale.isPM(input);
break;
- // 24 HOUR
- case 'H' : // fall through to hh
- case 'HH' : // fall through to hh
+ // HOUR
case 'h' : // fall through to hh
case 'hh' :
+ config._pf.bigHour = true;
+ /* falls through */
+ case 'H' : // fall through to HH
+ case 'HH' :
datePartArray[HOUR] = toInt(input);
break;
// MINUTE
@@ -1223,6 +1260,10 @@
case 'SSSS' :
datePartArray[MILLISECOND] = toInt(('0.' + input) * 1000);
break;
+ // UNIX OFFSET (MILLISECONDS)
+ case 'x':
+ config._d = new Date(toInt(input));
+ break;
// UNIX TIMESTAMP WITH MS
case 'X':
config._d = new Date(parseFloat(input) * 1000);
@@ -1359,12 +1400,25 @@
config._a[i] = input[i] = (config._a[i] == null) ? (i === 2 ? 1 : 0) : config._a[i];
}
+ // Check for 24:00:00.000
+ if (config._a[HOUR] === 24 &&
+ config._a[MINUTE] === 0 &&
+ config._a[SECOND] === 0 &&
+ config._a[MILLISECOND] === 0) {
+ config._nextDay = true;
+ config._a[HOUR] = 0;
+ }
+
config._d = (config._useUTC ? makeUTCDate : makeDate).apply(null, input);
// Apply timezone offset from input. The actual zone can be changed
// with parseZone.
if (config._tzm != null) {
config._d.setUTCMinutes(config._d.getUTCMinutes() + config._tzm);
}
+
+ if (config._nextDay) {
+ config._a[HOUR] = 24;
+ }
}
function dateFromObject(config) {
@@ -1378,7 +1432,7 @@
config._a = [
normalizedInput.year,
normalizedInput.month,
- normalizedInput.day,
+ normalizedInput.day || normalizedInput.date,
normalizedInput.hour,
normalizedInput.minute,
normalizedInput.second,
@@ -1451,6 +1505,10 @@
config._pf.unusedInput.push(string);
}
+ // clear _12h flag if hour is <= 12
+ if (config._pf.bigHour === true && config._a[HOUR] <= 12) {
+ config._pf.bigHour = undefined;
+ }
// handle am pm
if (config._isPm && config._a[HOUR] < 12) {
config._a[HOUR] += 12;
@@ -1459,7 +1517,6 @@
if (config._isPm === false && config._a[HOUR] === 12) {
config._a[HOUR] = 0;
}
-
dateFromConfig(config);
checkOverflow(config);
}
@@ -1719,7 +1776,8 @@
function makeMoment(config) {
var input = config._i,
- format = config._f;
+ format = config._f,
+ res;
config._locale = config._locale || moment.localeData(config._l);
@@ -1743,7 +1801,14 @@
makeDateFromInput(config);
}
- return new Moment(config);
+ res = new Moment(config);
+ if (res._nextDay) {
+ // Adding is smart enough around DST
+ res.add(1, 'd');
+ res._nextDay = undefined;
+ }
+
+ return res;
}
moment = function (input, format, locale, strict) {
@@ -1775,7 +1840,7 @@
'release. Please refer to ' +
'https://github.com/moment/moment/issues/1407 for more info.',
function (config) {
- config._d = new Date(config._i);
+ config._d = new Date(config._i + (config._useUTC ? ' UTC' : ''));
}
);
@@ -2087,7 +2152,12 @@
toISOString : function () {
var m = moment(this).utc();
if (0 < m.year() && m.year() <= 9999) {
- return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
+ if ('function' === typeof Date.prototype.toISOString) {
+ // native implementation is ~50x faster, use it when we can
+ return this.toDate().toISOString();
+ } else {
+ return formatMoment(m, 'YYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
+ }
} else {
return formatMoment(m, 'YYYYYY-MM-DD[T]HH:mm:ss.SSS[Z]');
}
@@ -2206,7 +2276,7 @@
diff < 1 ? 'sameDay' :
diff < 2 ? 'nextDay' :
diff < 7 ? 'nextWeek' : 'sameElse';
- return this.format(this.localeData().calendar(format, this));
+ return this.format(this.localeData().calendar(format, this, moment(now)));
},
isLeapYear : function () {
@@ -2275,36 +2345,45 @@
endOf: function (units) {
units = normalizeUnits(units);
+ if (units === undefined || units === 'millisecond') {
+ return this;
+ }
return this.startOf(units).add(1, (units === 'isoWeek' ? 'week' : units)).subtract(1, 'ms');
},
isAfter: function (input, units) {
+ var inputMs;
units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond');
if (units === 'millisecond') {
input = moment.isMoment(input) ? input : moment(input);
return +this > +input;
} else {
- return +this.clone().startOf(units) > +moment(input).startOf(units);
+ inputMs = moment.isMoment(input) ? +input : +moment(input);
+ return inputMs < +this.clone().startOf(units);
}
},
isBefore: function (input, units) {
+ var inputMs;
units = normalizeUnits(typeof units !== 'undefined' ? units : 'millisecond');
if (units === 'millisecond') {
input = moment.isMoment(input) ? input : moment(input);
return +this < +input;
} else {
- return +this.clone().startOf(units) < +moment(input).startOf(units);
+ inputMs = moment.isMoment(input) ? +input : +moment(input);
+ return +this.clone().endOf(units) < inputMs;
}
},
isSame: function (input, units) {
+ var inputMs;
units = normalizeUnits(units || 'millisecond');
if (units === 'millisecond') {
input = moment.isMoment(input) ? input : moment(input);
return +this === +input;
} else {
- return +this.clone().startOf(units) === +makeAs(input, this).startOf(units);
+ inputMs = +moment(input);
+ return +(this.clone().startOf(units)) <= inputMs && inputMs <= +(this.clone().endOf(units));
}
},
@@ -2481,7 +2560,7 @@
},
lang : deprecate(
- 'moment().lang() is deprecated. Use moment().localeData() instead.',
+ 'moment().lang() is deprecated. Instead, use moment().localeData() to get the language configuration. Use moment().locale() to change languages.',
function (key) {
if (key === undefined) {
return this.localeData();
@@ -2702,7 +2781,7 @@
return units === 'month' ? months : months / 12;
} else {
// handle milliseconds separately because of floating point math errors (issue #1867)
- days = this._days + yearsToDays(this._months / 12);
+ days = this._days + Math.round(yearsToDays(this._months / 12));
switch (units) {
case 'week': return days / 7 + this._milliseconds / 6048e5;
case 'day': return days + this._milliseconds / 864e5;
@@ -2804,6 +2883,7 @@
// Set default locale, other locale will inherit from English.
moment.locale('en', {
+ ordinalParse: /\d{1,2}(th|st|nd|rd)/,
ordinal : function (number) {
var b = number % 10,
output = (toInt(number % 100 / 10) === 1) ? 'th' :
diff --git a/resources/lib/mustache/mustache.js b/resources/lib/mustache/mustache.js
new file mode 100644
index 00000000..dbc98231
--- /dev/null
+++ b/resources/lib/mustache/mustache.js
@@ -0,0 +1,578 @@
+/*!
+ * mustache.js - Logic-less {{mustache}} templates with JavaScript
+ * http://github.com/janl/mustache.js
+ */
+
+/*global define: false*/
+
+(function (global, factory) {
+ if (typeof exports === "object" && exports) {
+ factory(exports); // CommonJS
+ } else if (typeof define === "function" && define.amd) {
+ define(['exports'], factory); // AMD
+ } else {
+ factory(global.Mustache = {}); // <script>
+ }
+}(this, function (mustache) {
+
+ var Object_toString = Object.prototype.toString;
+ var isArray = Array.isArray || function (object) {
+ return Object_toString.call(object) === '[object Array]';
+ };
+
+ function isFunction(object) {
+ return typeof object === 'function';
+ }
+
+ function escapeRegExp(string) {
+ return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&");
+ }
+
+ // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
+ // See https://github.com/janl/mustache.js/issues/189
+ var RegExp_test = RegExp.prototype.test;
+ function testRegExp(re, string) {
+ return RegExp_test.call(re, string);
+ }
+
+ var nonSpaceRe = /\S/;
+ function isWhitespace(string) {
+ return !testRegExp(nonSpaceRe, string);
+ }
+
+ var entityMap = {
+ "&": "&amp;",
+ "<": "&lt;",
+ ">": "&gt;",
+ '"': '&quot;',
+ "'": '&#39;',
+ "/": '&#x2F;'
+ };
+
+ function escapeHtml(string) {
+ return String(string).replace(/[&<>"'\/]/g, function (s) {
+ return entityMap[s];
+ });
+ }
+
+ var whiteRe = /\s*/;
+ var spaceRe = /\s+/;
+ var equalsRe = /\s*=/;
+ var curlyRe = /\s*\}/;
+ var tagRe = /#|\^|\/|>|\{|&|=|!/;
+
+ /**
+ * Breaks up the given `template` string into a tree of tokens. If the `tags`
+ * argument is given here it must be an array with two string values: the
+ * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
+ * course, the default is to use mustaches (i.e. mustache.tags).
+ *
+ * A token is an array with at least 4 elements. The first element is the
+ * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
+ * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
+ * all text that appears outside a symbol this element is "text".
+ *
+ * The second element of a token is its "value". For mustache tags this is
+ * whatever else was inside the tag besides the opening symbol. For text tokens
+ * this is the text itself.
+ *
+ * The third and fourth elements of the token are the start and end indices,
+ * respectively, of the token in the original template.
+ *
+ * Tokens that are the root node of a subtree contain two more elements: 1) an
+ * array of tokens in the subtree and 2) the index in the original template at
+ * which the closing tag for that section begins.
+ */
+ function parseTemplate(template, tags) {
+ if (!template)
+ return [];
+
+ var sections = []; // Stack to hold section tokens
+ var tokens = []; // Buffer to hold the tokens
+ var spaces = []; // Indices of whitespace tokens on the current line
+ var hasTag = false; // Is there a {{tag}} on the current line?
+ var nonSpace = false; // Is there a non-space char on the current line?
+
+ // Strips all whitespace tokens array for the current line
+ // if there was a {{#tag}} on it and otherwise only space.
+ function stripSpace() {
+ if (hasTag && !nonSpace) {
+ while (spaces.length)
+ delete tokens[spaces.pop()];
+ } else {
+ spaces = [];
+ }
+
+ hasTag = false;
+ nonSpace = false;
+ }
+
+ var openingTagRe, closingTagRe, closingCurlyRe;
+ function compileTags(tags) {
+ if (typeof tags === 'string')
+ tags = tags.split(spaceRe, 2);
+
+ if (!isArray(tags) || tags.length !== 2)
+ throw new Error('Invalid tags: ' + tags);
+
+ openingTagRe = new RegExp(escapeRegExp(tags[0]) + '\\s*');
+ closingTagRe = new RegExp('\\s*' + escapeRegExp(tags[1]));
+ closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tags[1]));
+ }
+
+ compileTags(tags || mustache.tags);
+
+ var scanner = new Scanner(template);
+
+ var start, type, value, chr, token, openSection;
+ while (!scanner.eos()) {
+ start = scanner.pos;
+
+ // Match any text between tags.
+ value = scanner.scanUntil(openingTagRe);
+
+ if (value) {
+ for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
+ chr = value.charAt(i);
+
+ if (isWhitespace(chr)) {
+ spaces.push(tokens.length);
+ } else {
+ nonSpace = true;
+ }
+
+ tokens.push([ 'text', chr, start, start + 1 ]);
+ start += 1;
+
+ // Check for whitespace on the current line.
+ if (chr === '\n')
+ stripSpace();
+ }
+ }
+
+ // Match the opening tag.
+ if (!scanner.scan(openingTagRe))
+ break;
+
+ hasTag = true;
+
+ // Get the tag type.
+ type = scanner.scan(tagRe) || 'name';
+ scanner.scan(whiteRe);
+
+ // Get the tag value.
+ if (type === '=') {
+ value = scanner.scanUntil(equalsRe);
+ scanner.scan(equalsRe);
+ scanner.scanUntil(closingTagRe);
+ } else if (type === '{') {
+ value = scanner.scanUntil(closingCurlyRe);
+ scanner.scan(curlyRe);
+ scanner.scanUntil(closingTagRe);
+ type = '&';
+ } else {
+ value = scanner.scanUntil(closingTagRe);
+ }
+
+ // Match the closing tag.
+ if (!scanner.scan(closingTagRe))
+ throw new Error('Unclosed tag at ' + scanner.pos);
+
+ token = [ type, value, start, scanner.pos ];
+ tokens.push(token);
+
+ if (type === '#' || type === '^') {
+ sections.push(token);
+ } else if (type === '/') {
+ // Check section nesting.
+ openSection = sections.pop();
+
+ if (!openSection)
+ throw new Error('Unopened section "' + value + '" at ' + start);
+
+ if (openSection[1] !== value)
+ throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
+ } else if (type === 'name' || type === '{' || type === '&') {
+ nonSpace = true;
+ } else if (type === '=') {
+ // Set the tags for the next time around.
+ compileTags(value);
+ }
+ }
+
+ // Make sure there are no open sections when we're done.
+ openSection = sections.pop();
+
+ if (openSection)
+ throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
+
+ return nestTokens(squashTokens(tokens));
+ }
+
+ /**
+ * Combines the values of consecutive text tokens in the given `tokens` array
+ * to a single token.
+ */
+ function squashTokens(tokens) {
+ var squashedTokens = [];
+
+ var token, lastToken;
+ for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
+ token = tokens[i];
+
+ if (token) {
+ if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
+ lastToken[1] += token[1];
+ lastToken[3] = token[3];
+ } else {
+ squashedTokens.push(token);
+ lastToken = token;
+ }
+ }
+ }
+
+ return squashedTokens;
+ }
+
+ /**
+ * Forms the given array of `tokens` into a nested tree structure where
+ * tokens that represent a section have two additional items: 1) an array of
+ * all tokens that appear in that section and 2) the index in the original
+ * template that represents the end of that section.
+ */
+ function nestTokens(tokens) {
+ var nestedTokens = [];
+ var collector = nestedTokens;
+ var sections = [];
+
+ var token, section;
+ for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
+ token = tokens[i];
+
+ switch (token[0]) {
+ case '#':
+ case '^':
+ collector.push(token);
+ sections.push(token);
+ collector = token[4] = [];
+ break;
+ case '/':
+ section = sections.pop();
+ section[5] = token[2];
+ collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
+ break;
+ default:
+ collector.push(token);
+ }
+ }
+
+ return nestedTokens;
+ }
+
+ /**
+ * A simple string scanner that is used by the template parser to find
+ * tokens in template strings.
+ */
+ function Scanner(string) {
+ this.string = string;
+ this.tail = string;
+ this.pos = 0;
+ }
+
+ /**
+ * Returns `true` if the tail is empty (end of string).
+ */
+ Scanner.prototype.eos = function () {
+ return this.tail === "";
+ };
+
+ /**
+ * Tries to match the given regular expression at the current position.
+ * Returns the matched text if it can match, the empty string otherwise.
+ */
+ Scanner.prototype.scan = function (re) {
+ var match = this.tail.match(re);
+
+ if (!match || match.index !== 0)
+ return '';
+
+ var string = match[0];
+
+ this.tail = this.tail.substring(string.length);
+ this.pos += string.length;
+
+ return string;
+ };
+
+ /**
+ * Skips all text until the given regular expression can be matched. Returns
+ * the skipped string, which is the entire tail if no match can be made.
+ */
+ Scanner.prototype.scanUntil = function (re) {
+ var index = this.tail.search(re), match;
+
+ switch (index) {
+ case -1:
+ match = this.tail;
+ this.tail = "";
+ break;
+ case 0:
+ match = "";
+ break;
+ default:
+ match = this.tail.substring(0, index);
+ this.tail = this.tail.substring(index);
+ }
+
+ this.pos += match.length;
+
+ return match;
+ };
+
+ /**
+ * Represents a rendering context by wrapping a view object and
+ * maintaining a reference to the parent context.
+ */
+ function Context(view, parentContext) {
+ this.view = view == null ? {} : view;
+ this.cache = { '.': this.view };
+ this.parent = parentContext;
+ }
+
+ /**
+ * Creates a new context using the given view with this context
+ * as the parent.
+ */
+ Context.prototype.push = function (view) {
+ return new Context(view, this);
+ };
+
+ /**
+ * Returns the value of the given name in this context, traversing
+ * up the context hierarchy if the value is absent in this context's view.
+ */
+ Context.prototype.lookup = function (name) {
+ var cache = this.cache;
+
+ var value;
+ if (name in cache) {
+ value = cache[name];
+ } else {
+ var context = this, names, index;
+
+ while (context) {
+ if (name.indexOf('.') > 0) {
+ value = context.view;
+ names = name.split('.');
+ index = 0;
+
+ while (value != null && index < names.length)
+ value = value[names[index++]];
+ } else if (typeof context.view == 'object') {
+ value = context.view[name];
+ }
+
+ if (value != null)
+ break;
+
+ context = context.parent;
+ }
+
+ cache[name] = value;
+ }
+
+ if (isFunction(value))
+ value = value.call(this.view);
+
+ return value;
+ };
+
+ /**
+ * A Writer knows how to take a stream of tokens and render them to a
+ * string, given a context. It also maintains a cache of templates to
+ * avoid the need to parse the same template twice.
+ */
+ function Writer() {
+ this.cache = {};
+ }
+
+ /**
+ * Clears all cached templates in this writer.
+ */
+ Writer.prototype.clearCache = function () {
+ this.cache = {};
+ };
+
+ /**
+ * Parses and caches the given `template` and returns the array of tokens
+ * that is generated from the parse.
+ */
+ Writer.prototype.parse = function (template, tags) {
+ var cache = this.cache;
+ var tokens = cache[template];
+
+ if (tokens == null)
+ tokens = cache[template] = parseTemplate(template, tags);
+
+ return tokens;
+ };
+
+ /**
+ * High-level method that is used to render the given `template` with
+ * the given `view`.
+ *
+ * The optional `partials` argument may be an object that contains the
+ * names and templates of partials that are used in the template. It may
+ * also be a function that is used to load partial templates on the fly
+ * that takes a single argument: the name of the partial.
+ */
+ Writer.prototype.render = function (template, view, partials) {
+ var tokens = this.parse(template);
+ var context = (view instanceof Context) ? view : new Context(view);
+ return this.renderTokens(tokens, context, partials, template);
+ };
+
+ /**
+ * Low-level method that renders the given array of `tokens` using
+ * the given `context` and `partials`.
+ *
+ * Note: The `originalTemplate` is only ever used to extract the portion
+ * of the original template that was contained in a higher-order section.
+ * If the template doesn't use higher-order sections, this argument may
+ * be omitted.
+ */
+ Writer.prototype.renderTokens = function (tokens, context, partials, originalTemplate) {
+ var buffer = '';
+
+ // This function is used to render an arbitrary template
+ // in the current context by higher-order sections.
+ var self = this;
+ function subRender(template) {
+ return self.render(template, context, partials);
+ }
+
+ var token, value;
+ for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
+ token = tokens[i];
+
+ switch (token[0]) {
+ case '#':
+ value = context.lookup(token[1]);
+
+ if (!value)
+ continue;
+
+ if (isArray(value)) {
+ for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
+ buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
+ }
+ } else if (typeof value === 'object' || typeof value === 'string') {
+ buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
+ } else if (isFunction(value)) {
+ if (typeof originalTemplate !== 'string')
+ throw new Error('Cannot use higher-order sections without the original template');
+
+ // Extract the portion of the original template that the section contains.
+ value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
+
+ if (value != null)
+ buffer += value;
+ } else {
+ buffer += this.renderTokens(token[4], context, partials, originalTemplate);
+ }
+
+ break;
+ case '^':
+ value = context.lookup(token[1]);
+
+ // Use JavaScript's definition of falsy. Include empty arrays.
+ // See https://github.com/janl/mustache.js/issues/186
+ if (!value || (isArray(value) && value.length === 0))
+ buffer += this.renderTokens(token[4], context, partials, originalTemplate);
+
+ break;
+ case '>':
+ if (!partials)
+ continue;
+
+ value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
+
+ if (value != null)
+ buffer += this.renderTokens(this.parse(value), context, partials, value);
+
+ break;
+ case '&':
+ value = context.lookup(token[1]);
+
+ if (value != null)
+ buffer += value;
+
+ break;
+ case 'name':
+ value = context.lookup(token[1]);
+
+ if (value != null)
+ buffer += mustache.escape(value);
+
+ break;
+ case 'text':
+ buffer += token[1];
+ break;
+ }
+ }
+
+ return buffer;
+ };
+
+ mustache.name = "mustache.js";
+ mustache.version = "0.8.2";
+ mustache.tags = [ "{{", "}}" ];
+
+ // All high-level mustache.* functions use this writer.
+ var defaultWriter = new Writer();
+
+ /**
+ * Clears all cached templates in the default writer.
+ */
+ mustache.clearCache = function () {
+ return defaultWriter.clearCache();
+ };
+
+ /**
+ * Parses and caches the given template in the default writer and returns the
+ * array of tokens it contains. Doing this ahead of time avoids the need to
+ * parse templates on the fly as they are rendered.
+ */
+ mustache.parse = function (template, tags) {
+ return defaultWriter.parse(template, tags);
+ };
+
+ /**
+ * Renders the `template` with the given `view` and `partials` using the
+ * default writer.
+ */
+ mustache.render = function (template, view, partials) {
+ return defaultWriter.render(template, view, partials);
+ };
+
+ // This is here for backwards compatibility with 0.4.x.
+ mustache.to_html = function (template, view, partials, send) {
+ var result = mustache.render(template, view, partials);
+
+ if (isFunction(send)) {
+ send(result);
+ } else {
+ return result;
+ }
+ };
+
+ // Export the escaping function so that the user may override it.
+ // See https://github.com/janl/mustache.js/issues/244
+ mustache.escape = escapeHtml;
+
+ // Export these mainly for testing, but also for advanced usage.
+ mustache.Scanner = Scanner;
+ mustache.Context = Context;
+ mustache.Writer = Writer;
+
+}));
diff --git a/resources/lib/oojs-ui/i18n/ace.json b/resources/lib/oojs-ui/i18n/ace.json
index b37e9bce..0fdc1a89 100644
--- a/resources/lib/oojs-ui/i18n/ace.json
+++ b/resources/lib/oojs-ui/i18n/ace.json
@@ -4,7 +4,6 @@
"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"
diff --git a/resources/lib/oojs-ui/i18n/af.json b/resources/lib/oojs-ui/i18n/af.json
index c5984af0..6f79e370 100644
--- a/resources/lib/oojs-ui/i18n/af.json
+++ b/resources/lib/oojs-ui/i18n/af.json
@@ -4,7 +4,16 @@
"Naudefj"
]
},
- "ooui-dialog-action-close": "Sluit",
"ooui-outline-control-move-down": "Skuif item af",
- "ooui-outline-control-move-up": "Skuif item op"
+ "ooui-outline-control-move-up": "Skuif item op",
+ "ooui-outline-control-remove": "Verwyder item",
+ "ooui-toolbar-more": "Meer",
+ "ooui-toolgroup-expand": "Meer",
+ "ooui-toolgroup-collapse": "Minder",
+ "ooui-dialog-message-accept": "Regso",
+ "ooui-dialog-message-reject": "Kanselleer",
+ "ooui-dialog-process-error": "Iets het verkeerd gegaan",
+ "ooui-dialog-process-dismiss": "Sluit",
+ "ooui-dialog-process-retry": "Probeer weer",
+ "ooui-dialog-process-continue": "Gaan voort"
}
diff --git a/resources/lib/oojs-ui/i18n/am.json b/resources/lib/oojs-ui/i18n/am.json
index 0e070c60..bfe9d5c3 100644
--- a/resources/lib/oojs-ui/i18n/am.json
+++ b/resources/lib/oojs-ui/i18n/am.json
@@ -3,6 +3,5 @@
"authors": [
"Elfalem"
]
- },
- "ooui-dialog-action-close": "ለመዝጋት"
+ }
}
diff --git a/resources/lib/oojs-ui/i18n/ar.json b/resources/lib/oojs-ui/i18n/ar.json
index b01e2cd4..058a1491 100644
--- a/resources/lib/oojs-ui/i18n/ar.json
+++ b/resources/lib/oojs-ui/i18n/ar.json
@@ -9,16 +9,20 @@
"OsamaK",
"زكريا",
"مشعل الحربي",
- "ترجمان05"
+ "ترجمان05",
+ "Abanima"
]
},
"ooui-outline-control-move-down": "انقل العنصر للأسفل",
"ooui-outline-control-move-up": "انقل العنصر للأعلى",
"ooui-outline-control-remove": "أزل العنصر",
"ooui-toolbar-more": "مزيد",
+ "ooui-toolgroup-expand": "مزيد",
+ "ooui-toolgroup-collapse": "أقل",
"ooui-dialog-message-accept": "موافق",
"ooui-dialog-message-reject": "ألغ",
"ooui-dialog-process-error": "حدث خطأ",
"ooui-dialog-process-dismiss": "أغلق",
- "ooui-dialog-process-retry": "حاول مرة أخرى"
+ "ooui-dialog-process-retry": "حاول مرة أخرى",
+ "ooui-dialog-process-continue": "استمر"
}
diff --git a/resources/lib/oojs-ui/i18n/arc.json b/resources/lib/oojs-ui/i18n/arc.json
index 7eb02a7b..de5b7aff 100644
--- a/resources/lib/oojs-ui/i18n/arc.json
+++ b/resources/lib/oojs-ui/i18n/arc.json
@@ -3,6 +3,5 @@
"authors": [
"Basharh"
]
- },
- "ooui-dialog-action-close": "ܣܟܘܪ"
+ }
}
diff --git a/resources/lib/oojs-ui/i18n/awa.json b/resources/lib/oojs-ui/i18n/awa.json
new file mode 100644
index 00000000..f78ed326
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/awa.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "1AnuraagPandey"
+ ]
+ },
+ "ooui-toolbar-more": "अउर"
+}
diff --git a/resources/lib/oojs-ui/i18n/az.json b/resources/lib/oojs-ui/i18n/az.json
index aa835e28..fc12d1b3 100644
--- a/resources/lib/oojs-ui/i18n/az.json
+++ b/resources/lib/oojs-ui/i18n/az.json
@@ -6,7 +6,6 @@
"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",
"ooui-outline-control-remove": "Bəndi sil",
diff --git a/resources/lib/oojs-ui/i18n/ba.json b/resources/lib/oojs-ui/i18n/ba.json
index 0bfa299b..ff915b06 100644
--- a/resources/lib/oojs-ui/i18n/ba.json
+++ b/resources/lib/oojs-ui/i18n/ba.json
@@ -9,7 +9,6 @@
"Рустам Нурыев"
]
},
- "ooui-dialog-action-close": "Ябырға",
"ooui-outline-control-move-down": "Аҫҡа күсерергә",
"ooui-outline-control-move-up": "Өҫкә күсерергә"
}
diff --git a/resources/lib/oojs-ui/i18n/bcc.json b/resources/lib/oojs-ui/i18n/bcc.json
new file mode 100644
index 00000000..a340a881
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/bcc.json
@@ -0,0 +1,9 @@
+{
+ "@metadata": {
+ "authors": [
+ "Baloch Afghanistan"
+ ]
+ },
+ "ooui-dialog-message-accept": "اوکی",
+ "ooui-dialog-process-retry": "پدا کوشش کورتین"
+}
diff --git a/resources/lib/oojs-ui/i18n/bcl.json b/resources/lib/oojs-ui/i18n/bcl.json
index f3db6398..bc2251e8 100644
--- a/resources/lib/oojs-ui/i18n/bcl.json
+++ b/resources/lib/oojs-ui/i18n/bcl.json
@@ -5,7 +5,6 @@
"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"
diff --git a/resources/lib/oojs-ui/i18n/be-tarask.json b/resources/lib/oojs-ui/i18n/be-tarask.json
index c3f1abfe..c5475f85 100644
--- a/resources/lib/oojs-ui/i18n/be-tarask.json
+++ b/resources/lib/oojs-ui/i18n/be-tarask.json
@@ -7,7 +7,6 @@
"Zedlik"
]
},
- "ooui-dialog-action-close": "Закрыць",
"ooui-outline-control-move-down": "Перасунуць ніжэй",
"ooui-outline-control-move-up": "Перасунуць вышэй",
"ooui-toolbar-more": "Болей"
diff --git a/resources/lib/oojs-ui/i18n/be.json b/resources/lib/oojs-ui/i18n/be.json
index 08fbe0b4..fb0f6880 100644
--- a/resources/lib/oojs-ui/i18n/be.json
+++ b/resources/lib/oojs-ui/i18n/be.json
@@ -5,9 +5,6 @@
"Artificial123"
]
},
- "ooui-dialog-action-close": "Закрыць",
- "ooui-dialog-confirm-title": "Пацвердзіць",
- "ooui-dialog-confirm-default-prompt": "Вы ўпэўненыя?",
- "ooui-dialog-confirm-default-ok": "ОК",
- "ooui-dialog-confirm-default-cancel": "Адмяніць"
+ "ooui-dialog-message-accept": "ОК",
+ "ooui-dialog-message-reject": "Адмяніць"
}
diff --git a/resources/lib/oojs-ui/i18n/bg.json b/resources/lib/oojs-ui/i18n/bg.json
index c2839736..02d95b52 100644
--- a/resources/lib/oojs-ui/i18n/bg.json
+++ b/resources/lib/oojs-ui/i18n/bg.json
@@ -7,7 +7,6 @@
"Mitzev"
]
},
- "ooui-dialog-action-close": "Затваряне",
"ooui-outline-control-remove": "Премахване на обекта",
"ooui-toolbar-more": "Още"
}
diff --git a/resources/lib/oojs-ui/i18n/bn.json b/resources/lib/oojs-ui/i18n/bn.json
index f7105ce7..1cfa6c45 100644
--- a/resources/lib/oojs-ui/i18n/bn.json
+++ b/resources/lib/oojs-ui/i18n/bn.json
@@ -6,15 +6,21 @@
"Jayantanth",
"Nasir8891",
"Runab",
- "Sayak Sarkar"
+ "Sayak Sarkar",
+ "Aftabuzzaman",
+ "RYasmeen (WMF)"
]
},
- "ooui-dialog-action-close": "বন্ধ",
"ooui-outline-control-move-down": "আইটেম নিচে স্থানান্তর",
"ooui-outline-control-move-up": "আইটেম উপরে স্থানান্তর",
"ooui-outline-control-remove": "আইটেম সরান",
"ooui-toolbar-more": "আরও",
- "ooui-dialog-confirm-title": "নিশ্চিত করুন",
- "ooui-dialog-confirm-default-ok": "ঠিক আছে",
- "ooui-dialog-confirm-default-cancel": "বাতিল"
+ "ooui-toolgroup-expand": "আরও",
+ "ooui-toolgroup-collapse": "কম দেখাও",
+ "ooui-dialog-message-accept": "ঠিক আছে",
+ "ooui-dialog-message-reject": "বাতিল",
+ "ooui-dialog-process-error": "কিছু একটায় ত্রুটি হয়েছে",
+ "ooui-dialog-process-dismiss": "বাতিল করুন",
+ "ooui-dialog-process-retry": "আবার চেষ্টা করুন",
+ "ooui-dialog-process-continue": "অগ্রসর হোন"
}
diff --git a/resources/lib/oojs-ui/i18n/br.json b/resources/lib/oojs-ui/i18n/br.json
index 69591917..83af863c 100644
--- a/resources/lib/oojs-ui/i18n/br.json
+++ b/resources/lib/oojs-ui/i18n/br.json
@@ -3,16 +3,20 @@
"authors": [
"Fohanno",
"Fulup",
- "Y-M D"
+ "Y-M D",
+ "Maoris"
]
},
"ooui-outline-control-move-down": "Lakaat an elfenn da ziskenn",
"ooui-outline-control-move-up": "Lakaat an elfenn da bignat",
"ooui-outline-control-remove": "Tennañ an elfenn",
"ooui-toolbar-more": "Muioc'h",
+ "ooui-toolgroup-expand": "Muioc'h",
+ "ooui-toolgroup-collapse": "Nebeutoc'h",
"ooui-dialog-message-accept": "Mat eo",
"ooui-dialog-message-reject": "Nullañ",
"ooui-dialog-process-error": "Un dra bennak a-dreuz a zo bet",
"ooui-dialog-process-dismiss": "Disteurel",
- "ooui-dialog-process-retry": "Klask en-dro"
+ "ooui-dialog-process-retry": "Klask en-dro",
+ "ooui-dialog-process-continue": "Kenderc'hel"
}
diff --git a/resources/lib/oojs-ui/i18n/bs.json b/resources/lib/oojs-ui/i18n/bs.json
index 14280a79..130bd8e5 100644
--- a/resources/lib/oojs-ui/i18n/bs.json
+++ b/resources/lib/oojs-ui/i18n/bs.json
@@ -4,13 +4,16 @@
"DzWiki"
]
},
- "ooui-dialog-action-close": "Zatvori",
"ooui-outline-control-move-down": "Premjesti stavku dole",
"ooui-outline-control-move-up": "Premjesti stavku gore",
"ooui-outline-control-remove": "Ukloni stavku",
"ooui-toolbar-more": "Više",
- "ooui-dialog-confirm-title": "Potvrdi",
- "ooui-dialog-confirm-default-prompt": "Da li ste sigurni?",
- "ooui-dialog-confirm-default-ok": "U redu",
- "ooui-dialog-confirm-default-cancel": "Otkaži"
+ "ooui-toolgroup-expand": "Više",
+ "ooui-toolgroup-collapse": "Manje",
+ "ooui-dialog-message-accept": "U redu",
+ "ooui-dialog-message-reject": "Otkaži",
+ "ooui-dialog-process-error": "Nešto je pošlo naopako",
+ "ooui-dialog-process-dismiss": "Odbaci",
+ "ooui-dialog-process-retry": "Pokušajte ponovo",
+ "ooui-dialog-process-continue": "Nastavi"
}
diff --git a/resources/lib/oojs-ui/i18n/ca.json b/resources/lib/oojs-ui/i18n/ca.json
index c3e80fea..ce3afa43 100644
--- a/resources/lib/oojs-ui/i18n/ca.json
+++ b/resources/lib/oojs-ui/i18n/ca.json
@@ -9,12 +9,20 @@
"SMP",
"Vriullop",
"Toniher",
- "Edustus"
+ "Edustus",
+ "Davidpar"
]
},
- "ooui-outline-control-move-down": "Baixa element",
- "ooui-outline-control-move-up": "Puja element",
+ "ooui-outline-control-move-down": "Baixa l'element",
+ "ooui-outline-control-move-up": "Puja l'element",
+ "ooui-outline-control-remove": "Esborra l'ítem",
"ooui-toolbar-more": "Més",
+ "ooui-toolgroup-expand": "Més",
+ "ooui-toolgroup-collapse": "Menys",
+ "ooui-dialog-message-accept": "D'acord",
+ "ooui-dialog-message-reject": "Cancel·la",
+ "ooui-dialog-process-error": "Alguna cosa no ha funcionat",
"ooui-dialog-process-dismiss": "Descarta",
- "ooui-dialog-process-retry": "Torneu-ho a provar"
+ "ooui-dialog-process-retry": "Torneu-ho a provar",
+ "ooui-dialog-process-continue": "Continua"
}
diff --git a/resources/lib/oojs-ui/i18n/ce.json b/resources/lib/oojs-ui/i18n/ce.json
index de86daf0..562dc3d5 100644
--- a/resources/lib/oojs-ui/i18n/ce.json
+++ b/resources/lib/oojs-ui/i18n/ce.json
@@ -5,13 +5,13 @@
"Умар"
]
},
- "ooui-dialog-action-close": "ДӀачӀагӀа",
"ooui-outline-control-move-down": "Лаха яккха элемент",
"ooui-outline-control-move-up": "Лаккха яккха элемент",
"ooui-outline-control-remove": "ДӀадаха меттиг",
"ooui-toolbar-more": "Кхин",
- "ooui-dialog-confirm-title": "Бакъдан",
- "ooui-dialog-confirm-default-prompt": "Бакъалла лаьий хӀуна?",
- "ooui-dialog-confirm-default-ok": "ХӀаъ",
- "ooui-dialog-confirm-default-cancel": "Цаоьшу"
+ "ooui-toolgroup-expand": "Дукха",
+ "ooui-toolgroup-collapse": "КӀезиг",
+ "ooui-dialog-message-accept": "ХӀаъ",
+ "ooui-dialog-message-reject": "Цаоьшу",
+ "ooui-dialog-process-continue": "Кхин дӀа"
}
diff --git a/resources/lib/oojs-ui/i18n/ckb.json b/resources/lib/oojs-ui/i18n/ckb.json
index eadae998..0c66619d 100644
--- a/resources/lib/oojs-ui/i18n/ckb.json
+++ b/resources/lib/oojs-ui/i18n/ckb.json
@@ -6,8 +6,6 @@
"Serwan"
]
},
- "ooui-dialog-action-close": "دایخە",
- "ooui-dialog-confirm-default-prompt": "ئایا تۆ دڵنیات ؟",
- "ooui-dialog-confirm-default-ok": "باشە",
- "ooui-dialog-confirm-default-cancel": "پاشگەزبوونەوە"
+ "ooui-dialog-message-accept": "باشە",
+ "ooui-dialog-message-reject": "پاشگەزبوونەوە"
}
diff --git a/resources/lib/oojs-ui/i18n/co.json b/resources/lib/oojs-ui/i18n/co.json
index 19c2f5cd..01d181d7 100644
--- a/resources/lib/oojs-ui/i18n/co.json
+++ b/resources/lib/oojs-ui/i18n/co.json
@@ -4,7 +4,6 @@
"Paulu"
]
},
- "ooui-dialog-action-close": "Chjude",
"ooui-outline-control-move-down": "Fà falà l'ogettu",
"ooui-outline-control-move-up": "Fà cullà l'ogettu"
}
diff --git a/resources/lib/oojs-ui/i18n/crh-cyrl.json b/resources/lib/oojs-ui/i18n/crh-cyrl.json
new file mode 100644
index 00000000..ccc00269
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/crh-cyrl.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Don Alessandro"
+ ]
+ },
+ "ooui-toolbar-more": "Даа зияде"
+}
diff --git a/resources/lib/oojs-ui/i18n/crh-latn.json b/resources/lib/oojs-ui/i18n/crh-latn.json
new file mode 100644
index 00000000..7ad7b0bb
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/crh-latn.json
@@ -0,0 +1,8 @@
+{
+ "@metadata": {
+ "authors": [
+ "Don Alessandro"
+ ]
+ },
+ "ooui-toolbar-more": "Daa ziyade"
+}
diff --git a/resources/lib/oojs-ui/i18n/cs.json b/resources/lib/oojs-ui/i18n/cs.json
index a75cf0ba..1db9aed5 100644
--- a/resources/lib/oojs-ui/i18n/cs.json
+++ b/resources/lib/oojs-ui/i18n/cs.json
@@ -10,16 +10,20 @@
"Mormegil",
"Polda18",
"Tchoř",
- "ශ්වෙත"
+ "ශ්වෙත",
+ "Vojtěch Dostál"
]
},
"ooui-outline-control-move-down": "Přesunout položku dolů",
"ooui-outline-control-move-up": "Přesunout položku nahoru",
"ooui-outline-control-remove": "Odstranit položku",
"ooui-toolbar-more": "Další",
+ "ooui-toolgroup-expand": "Více",
+ "ooui-toolgroup-collapse": "Méně",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Storno",
"ooui-dialog-process-error": "Něco se pokazilo",
"ooui-dialog-process-dismiss": "Zavřít",
- "ooui-dialog-process-retry": "Zkusit znovu"
+ "ooui-dialog-process-retry": "Zkusit znovu",
+ "ooui-dialog-process-continue": "Pokračovat"
}
diff --git a/resources/lib/oojs-ui/i18n/cu.json b/resources/lib/oojs-ui/i18n/cu.json
index 45cd2012..aa916af0 100644
--- a/resources/lib/oojs-ui/i18n/cu.json
+++ b/resources/lib/oojs-ui/i18n/cu.json
@@ -4,6 +4,6 @@
"ОйЛ"
]
},
- "ooui-dialog-action-close": "ꙁакрꙑи",
- "ooui-toolbar-more": "вѧщє"
+ "ooui-toolbar-more": "вѧщє",
+ "ooui-toolgroup-expand": "вѧщє"
}
diff --git a/resources/lib/oojs-ui/i18n/cy.json b/resources/lib/oojs-ui/i18n/cy.json
index ff712519..b74cd064 100644
--- a/resources/lib/oojs-ui/i18n/cy.json
+++ b/resources/lib/oojs-ui/i18n/cy.json
@@ -7,7 +7,6 @@
"DChan (WMF)"
]
},
- "ooui-dialog-action-close": "Cau",
"ooui-outline-control-move-down": "Symud yr eitem i lawr",
"ooui-outline-control-move-up": "Symud yr eitem i fyny",
"ooui-outline-control-remove": "Tynnu'r eitem",
diff --git a/resources/lib/oojs-ui/i18n/da.json b/resources/lib/oojs-ui/i18n/da.json
index 156a6bc1..0b847be1 100644
--- a/resources/lib/oojs-ui/i18n/da.json
+++ b/resources/lib/oojs-ui/i18n/da.json
@@ -10,7 +10,6 @@
"Tehnix"
]
},
- "ooui-dialog-action-close": "Luk",
"ooui-outline-control-move-down": "Flyt ned",
"ooui-outline-control-move-up": "Flyt op",
"ooui-toolbar-more": "Mere"
diff --git a/resources/lib/oojs-ui/i18n/de.json b/resources/lib/oojs-ui/i18n/de.json
index 546689b9..15624fd4 100644
--- a/resources/lib/oojs-ui/i18n/de.json
+++ b/resources/lib/oojs-ui/i18n/de.json
@@ -17,9 +17,12 @@
"ooui-outline-control-move-up": "Element nach oben verschieben",
"ooui-outline-control-remove": "Element entfernen",
"ooui-toolbar-more": "Mehr",
+ "ooui-toolgroup-expand": "Mehr",
+ "ooui-toolgroup-collapse": "Weniger",
"ooui-dialog-message-accept": "Okay",
"ooui-dialog-message-reject": "Abbrechen",
"ooui-dialog-process-error": "Etwas ist schief gelaufen",
"ooui-dialog-process-dismiss": "Ausblenden",
- "ooui-dialog-process-retry": "Erneut versuchen"
+ "ooui-dialog-process-retry": "Erneut versuchen",
+ "ooui-dialog-process-continue": "Fortfahren"
}
diff --git a/resources/lib/oojs-ui/i18n/diq.json b/resources/lib/oojs-ui/i18n/diq.json
index 09415fd2..881ff674 100644
--- a/resources/lib/oojs-ui/i18n/diq.json
+++ b/resources/lib/oojs-ui/i18n/diq.json
@@ -9,7 +9,6 @@
"Se4598"
]
},
- "ooui-dialog-action-close": "Racnê",
"ooui-outline-control-move-down": "Bendi bere cêr",
"ooui-outline-control-move-up": "Bendi bere cor",
"ooui-outline-control-remove": "Obcey wedare",
diff --git a/resources/lib/oojs-ui/i18n/dsb.json b/resources/lib/oojs-ui/i18n/dsb.json
index d963ac89..7ad3f200 100644
--- a/resources/lib/oojs-ui/i18n/dsb.json
+++ b/resources/lib/oojs-ui/i18n/dsb.json
@@ -4,7 +4,6 @@
"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-outline-control-remove": "Zapisk wótpóraś",
diff --git a/resources/lib/oojs-ui/i18n/egl.json b/resources/lib/oojs-ui/i18n/egl.json
index d4ef2d56..624ecaa3 100644
--- a/resources/lib/oojs-ui/i18n/egl.json
+++ b/resources/lib/oojs-ui/i18n/egl.json
@@ -5,13 +5,10 @@
"Gloria sah"
]
},
- "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-outline-control-remove": "Armōv l'elemèint",
"ooui-toolbar-more": "Êter",
- "ooui-dialog-confirm-title": "Cunfermèr",
- "ooui-dialog-confirm-default-prompt": "Sî-'v sicùr?",
- "ooui-dialog-confirm-default-ok": "'D acòrdi",
- "ooui-dialog-confirm-default-cancel": "Scanślèr"
+ "ooui-dialog-message-accept": "'D acòrdi",
+ "ooui-dialog-message-reject": "Scanślèr"
}
diff --git a/resources/lib/oojs-ui/i18n/el.json b/resources/lib/oojs-ui/i18n/el.json
index cddd46e6..6fb7dbad 100644
--- a/resources/lib/oojs-ui/i18n/el.json
+++ b/resources/lib/oojs-ui/i18n/el.json
@@ -15,9 +15,12 @@
"ooui-outline-control-move-up": "Μετακίνηση στοιχείου προς τα επάνω",
"ooui-outline-control-remove": "Αφαίρεση στοιχείου",
"ooui-toolbar-more": "Περισσότερα",
+ "ooui-toolgroup-expand": "Περισσότερα",
+ "ooui-toolgroup-collapse": "Λιγότερα",
"ooui-dialog-message-accept": "ΟΚ",
"ooui-dialog-message-reject": "Ακύρωση",
"ooui-dialog-process-error": "Κάτι πήγε στραβά",
"ooui-dialog-process-dismiss": "Απόρριψη",
- "ooui-dialog-process-retry": "Δοκιμάστε ξανά"
+ "ooui-dialog-process-retry": "Δοκιμάστε ξανά",
+ "ooui-dialog-process-continue": "Συνέχεια"
}
diff --git a/resources/lib/oojs-ui/i18n/eml.json b/resources/lib/oojs-ui/i18n/eml.json
index 0b54f41d..6d9e8bf0 100644
--- a/resources/lib/oojs-ui/i18n/eml.json
+++ b/resources/lib/oojs-ui/i18n/eml.json
@@ -5,13 +5,10 @@
"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 êlta",
"ooui-outline-control-remove": "Tór vìa 'l elemèint",
"ooui-toolbar-more": "Êter",
- "ooui-dialog-confirm-title": "Cunfirmèr",
- "ooui-dialog-confirm-default-prompt": "Sî-'v sicùr?",
- "ooui-dialog-confirm-default-ok": "'D acòrdi",
- "ooui-dialog-confirm-default-cancel": "Scanślèr"
+ "ooui-dialog-message-accept": "'D acòrdi",
+ "ooui-dialog-message-reject": "Scanślèr"
}
diff --git a/resources/lib/oojs-ui/i18n/en.json b/resources/lib/oojs-ui/i18n/en.json
index 9e99440c..1db3fd85 100644
--- a/resources/lib/oojs-ui/i18n/en.json
+++ b/resources/lib/oojs-ui/i18n/en.json
@@ -20,9 +20,12 @@
"ooui-outline-control-move-up": "Move item up",
"ooui-outline-control-remove": "Remove item",
"ooui-toolbar-more": "More",
+ "ooui-toolgroup-expand": "More",
+ "ooui-toolgroup-collapse": "Fewer",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Cancel",
"ooui-dialog-process-error": "Something went wrong",
"ooui-dialog-process-dismiss": "Dismiss",
- "ooui-dialog-process-retry": "Try again"
+ "ooui-dialog-process-retry": "Try again",
+ "ooui-dialog-process-continue": "Continue"
}
diff --git a/resources/lib/oojs-ui/i18n/eo.json b/resources/lib/oojs-ui/i18n/eo.json
index 101f0af7..8d9714c6 100644
--- a/resources/lib/oojs-ui/i18n/eo.json
+++ b/resources/lib/oojs-ui/i18n/eo.json
@@ -7,7 +7,6 @@
"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"
diff --git a/resources/lib/oojs-ui/i18n/es.json b/resources/lib/oojs-ui/i18n/es.json
index 7660d4a9..915791e6 100644
--- a/resources/lib/oojs-ui/i18n/es.json
+++ b/resources/lib/oojs-ui/i18n/es.json
@@ -22,9 +22,12 @@
"ooui-outline-control-move-up": "Subir elemento",
"ooui-outline-control-remove": "Eliminar elemento",
"ooui-toolbar-more": "Más",
+ "ooui-toolgroup-expand": "Más",
+ "ooui-toolgroup-collapse": "Menos",
"ooui-dialog-message-accept": "Aceptar",
"ooui-dialog-message-reject": "Cancelar",
"ooui-dialog-process-error": "Algo salió mal",
"ooui-dialog-process-dismiss": "Descartar",
- "ooui-dialog-process-retry": "Intentar de nuevo"
+ "ooui-dialog-process-retry": "Intentar de nuevo",
+ "ooui-dialog-process-continue": "Continuar"
}
diff --git a/resources/lib/oojs-ui/i18n/et.json b/resources/lib/oojs-ui/i18n/et.json
index ac3af74e..6a212b6b 100644
--- a/resources/lib/oojs-ui/i18n/et.json
+++ b/resources/lib/oojs-ui/i18n/et.json
@@ -9,9 +9,12 @@
"ooui-outline-control-move-up": "Liiguta üksust ülespoole",
"ooui-outline-control-remove": "Eemalda üksus",
"ooui-toolbar-more": "Veel",
+ "ooui-toolgroup-expand": "Veel",
+ "ooui-toolgroup-collapse": "Vähem",
"ooui-dialog-message-accept": "Sobib",
"ooui-dialog-message-reject": "Loobu",
"ooui-dialog-process-error": "Midagi läks valesti",
"ooui-dialog-process-dismiss": "Hülga",
- "ooui-dialog-process-retry": "Proovi uuesti"
+ "ooui-dialog-process-retry": "Proovi uuesti",
+ "ooui-dialog-process-continue": "Jätka"
}
diff --git a/resources/lib/oojs-ui/i18n/eu.json b/resources/lib/oojs-ui/i18n/eu.json
index f1ce0bba..e947582d 100644
--- a/resources/lib/oojs-ui/i18n/eu.json
+++ b/resources/lib/oojs-ui/i18n/eu.json
@@ -3,11 +3,18 @@
"authors": [
"An13sa",
"Unai Fdz. de Betoño",
- "Xabier Armendaritz"
+ "Xabier Armendaritz",
+ "Subi"
]
},
- "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"
+ "ooui-toolbar-more": "Gehiago",
+ "ooui-toolgroup-expand": "Gehiago",
+ "ooui-toolgroup-collapse": "Gutxiago",
+ "ooui-dialog-message-accept": "Ados",
+ "ooui-dialog-message-reject": "Utzi",
+ "ooui-dialog-process-error": "Zerbaitek huts egin du",
+ "ooui-dialog-process-retry": "Saiatu berriro",
+ "ooui-dialog-process-continue": "Jarraitu"
}
diff --git a/resources/lib/oojs-ui/i18n/fa.json b/resources/lib/oojs-ui/i18n/fa.json
index b0ec8030..7cfcfa21 100644
--- a/resources/lib/oojs-ui/i18n/fa.json
+++ b/resources/lib/oojs-ui/i18n/fa.json
@@ -10,16 +10,20 @@
"Reza1615",
"Taha",
"درفش کاویانی",
- "Armin1392"
+ "Armin1392",
+ "Alirezaaa"
]
},
"ooui-outline-control-move-down": "انتقال مورد به پایین",
"ooui-outline-control-move-up": "انتقال مورد به بالا",
"ooui-outline-control-remove": "حذف مورد",
"ooui-toolbar-more": "بیشتر",
+ "ooui-toolgroup-expand": "بیشتر",
+ "ooui-toolgroup-collapse": "کمتر",
"ooui-dialog-message-accept": "تأیید",
"ooui-dialog-message-reject": "لغو",
"ooui-dialog-process-error": "مشکلی وجود دارد",
"ooui-dialog-process-dismiss": "نپذیرفتن",
- "ooui-dialog-process-retry": "دوباره امتحان کن"
+ "ooui-dialog-process-retry": "دوباره امتحان کن",
+ "ooui-dialog-process-continue": "ادامه"
}
diff --git a/resources/lib/oojs-ui/i18n/fi.json b/resources/lib/oojs-ui/i18n/fi.json
index efaabed5..3fb4110c 100644
--- a/resources/lib/oojs-ui/i18n/fi.json
+++ b/resources/lib/oojs-ui/i18n/fi.json
@@ -20,9 +20,12 @@
"ooui-outline-control-move-up": "Siirrä kohdetta ylöspäin",
"ooui-outline-control-remove": "Poista kohde",
"ooui-toolbar-more": "Lisää",
+ "ooui-toolgroup-expand": "Enemmän",
+ "ooui-toolgroup-collapse": "Vähemmän",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Peruuta",
"ooui-dialog-process-error": "Jokin meni pieleen",
"ooui-dialog-process-dismiss": "Hylkää",
- "ooui-dialog-process-retry": "Yritä uudelleen"
+ "ooui-dialog-process-retry": "Yritä uudelleen",
+ "ooui-dialog-process-continue": "Jatka"
}
diff --git a/resources/lib/oojs-ui/i18n/fo.json b/resources/lib/oojs-ui/i18n/fo.json
index 1810080f..6230cc9b 100644
--- a/resources/lib/oojs-ui/i18n/fo.json
+++ b/resources/lib/oojs-ui/i18n/fo.json
@@ -4,8 +4,16 @@
"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"
+ "ooui-outline-control-remove": "Tak ein lut burtur",
+ "ooui-toolbar-more": "Meira",
+ "ooui-toolgroup-expand": "Meira",
+ "ooui-toolgroup-collapse": "Færri",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Avbrót",
+ "ooui-dialog-process-error": "Okkurt gekk galið",
+ "ooui-dialog-process-dismiss": "Lat aftur",
+ "ooui-dialog-process-retry": "Royn aftur",
+ "ooui-dialog-process-continue": "Halt fram"
}
diff --git a/resources/lib/oojs-ui/i18n/fr.json b/resources/lib/oojs-ui/i18n/fr.json
index 8ff54750..9144cb01 100644
--- a/resources/lib/oojs-ui/i18n/fr.json
+++ b/resources/lib/oojs-ui/i18n/fr.json
@@ -26,16 +26,20 @@
"Urhixidur",
"Verdy p",
"Wyz",
- "SnowedEarth"
+ "SnowedEarth",
+ "Jdforrester"
]
},
"ooui-outline-control-move-down": "Faire descendre l’élément",
"ooui-outline-control-move-up": "Faire monter l’élément",
"ooui-outline-control-remove": "Supprimer l’élément",
"ooui-toolbar-more": "Plus",
+ "ooui-toolgroup-expand": "Plus",
+ "ooui-toolgroup-collapse": "Moins",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Annuler",
"ooui-dialog-process-error": "Quelque chose a mal tourné",
"ooui-dialog-process-dismiss": "Rejeter",
- "ooui-dialog-process-retry": "Réessayez"
+ "ooui-dialog-process-retry": "Réessayez",
+ "ooui-dialog-process-continue": "Continuer"
}
diff --git a/resources/lib/oojs-ui/i18n/frr.json b/resources/lib/oojs-ui/i18n/frr.json
index d98f4abd..54d0fb22 100644
--- a/resources/lib/oojs-ui/i18n/frr.json
+++ b/resources/lib/oojs-ui/i18n/frr.json
@@ -5,7 +5,6 @@
"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-outline-control-remove": "Element wechnem",
diff --git a/resources/lib/oojs-ui/i18n/fur.json b/resources/lib/oojs-ui/i18n/fur.json
index e1c129b6..83c2fd9e 100644
--- a/resources/lib/oojs-ui/i18n/fur.json
+++ b/resources/lib/oojs-ui/i18n/fur.json
@@ -5,7 +5,6 @@
"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"
diff --git a/resources/lib/oojs-ui/i18n/fy.json b/resources/lib/oojs-ui/i18n/fy.json
new file mode 100644
index 00000000..ddf9ff75
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/fy.json
@@ -0,0 +1,11 @@
+{
+ "@metadata": {
+ "authors": [
+ "Robin0van0der0vliet"
+ ]
+ },
+ "ooui-toolbar-more": "Mear",
+ "ooui-toolgroup-expand": "Mear",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Annulearje"
+}
diff --git a/resources/lib/oojs-ui/i18n/gl.json b/resources/lib/oojs-ui/i18n/gl.json
index eac992fd..a4339f47 100644
--- a/resources/lib/oojs-ui/i18n/gl.json
+++ b/resources/lib/oojs-ui/i18n/gl.json
@@ -3,16 +3,20 @@
"authors": [
"Alison",
"Kscanne",
- "Toliño"
+ "Toliño",
+ "Elisardojm"
]
},
"ooui-outline-control-move-down": "Mover o elemento abaixo",
"ooui-outline-control-move-up": "Mover o elemento arriba",
"ooui-outline-control-remove": "Eliminar o elemento",
"ooui-toolbar-more": "Máis",
+ "ooui-toolgroup-expand": "Máis",
+ "ooui-toolgroup-collapse": "Menos",
"ooui-dialog-message-accept": "Aceptar",
"ooui-dialog-message-reject": "Cancelar",
"ooui-dialog-process-error": "Algo foi mal",
"ooui-dialog-process-dismiss": "Agochar",
- "ooui-dialog-process-retry": "Inténteo de novo"
+ "ooui-dialog-process-retry": "Inténteo de novo",
+ "ooui-dialog-process-continue": "Continuar"
}
diff --git a/resources/lib/oojs-ui/i18n/he.json b/resources/lib/oojs-ui/i18n/he.json
index bbaf4c1f..cadc416c 100644
--- a/resources/lib/oojs-ui/i18n/he.json
+++ b/resources/lib/oojs-ui/i18n/he.json
@@ -19,9 +19,12 @@
"ooui-outline-control-move-up": "להזיז את הפריט מעלה",
"ooui-outline-control-remove": "להסיר את הפריט",
"ooui-toolbar-more": "עוד",
+ "ooui-toolgroup-expand": "יותר",
+ "ooui-toolgroup-collapse": "פחות",
"ooui-dialog-message-accept": "אישור",
"ooui-dialog-message-reject": "ביטול",
"ooui-dialog-process-error": "משהו השתבש",
"ooui-dialog-process-dismiss": "לוותר",
- "ooui-dialog-process-retry": "לנסות שוב"
+ "ooui-dialog-process-retry": "לנסות שוב",
+ "ooui-dialog-process-continue": "המשך"
}
diff --git a/resources/lib/oojs-ui/i18n/hi.json b/resources/lib/oojs-ui/i18n/hi.json
index 5a9bef0d..ce86aaab 100644
--- a/resources/lib/oojs-ui/i18n/hi.json
+++ b/resources/lib/oojs-ui/i18n/hi.json
@@ -5,12 +5,20 @@
"Devayon",
"Rajesh",
"Siddhartha Ghai",
- "Goelujjwal"
+ "Goelujjwal",
+ "Ankita-ks"
]
},
- "ooui-dialog-action-close": "बंद करें",
"ooui-outline-control-move-down": "प्रविष्टि नीचे ले जाएँ",
"ooui-outline-control-move-up": "प्रविष्टि ऊपर ले जाएँ",
"ooui-outline-control-remove": "आइटम हटाएँ",
- "ooui-toolbar-more": "अधिक"
+ "ooui-toolbar-more": "अधिक",
+ "ooui-toolgroup-expand": "अधिक",
+ "ooui-toolgroup-collapse": "कम",
+ "ooui-dialog-message-accept": "ठीक है",
+ "ooui-dialog-message-reject": "रद्द करें",
+ "ooui-dialog-process-error": "कुछ गलत हुअा है",
+ "ooui-dialog-process-dismiss": "ख़ारिज करें",
+ "ooui-dialog-process-retry": "पुनः प्रयास करें",
+ "ooui-dialog-process-continue": "जारी रखें"
}
diff --git a/resources/lib/oojs-ui/i18n/hr.json b/resources/lib/oojs-ui/i18n/hr.json
index c3724cfa..91188984 100644
--- a/resources/lib/oojs-ui/i18n/hr.json
+++ b/resources/lib/oojs-ui/i18n/hr.json
@@ -11,6 +11,8 @@
"ooui-outline-control-move-up": "Premjesti stavku gore",
"ooui-outline-control-remove": "Ukloni",
"ooui-toolbar-more": "Više",
+ "ooui-toolgroup-expand": "Više",
+ "ooui-toolgroup-collapse": "Manje",
"ooui-dialog-message-accept": "U redu",
"ooui-dialog-message-reject": "Odustani",
"ooui-dialog-process-error": "Nešto je pošlo po zlu",
diff --git a/resources/lib/oojs-ui/i18n/hsb.json b/resources/lib/oojs-ui/i18n/hsb.json
index 371b4f35..00894e4e 100644
--- a/resources/lib/oojs-ui/i18n/hsb.json
+++ b/resources/lib/oojs-ui/i18n/hsb.json
@@ -5,9 +5,16 @@
"Michawiki"
]
},
- "ooui-dialog-action-close": "Začinić",
"ooui-outline-control-move-down": "Zapisk dele přesunyć",
"ooui-outline-control-move-up": "Zapisk horje přesunyć",
"ooui-outline-control-remove": "Zapisk wotstronić",
- "ooui-toolbar-more": "Wjace"
+ "ooui-toolbar-more": "Wjace",
+ "ooui-toolgroup-expand": "Wjace",
+ "ooui-toolgroup-collapse": "Mjenje",
+ "ooui-dialog-message-accept": "W porjadku",
+ "ooui-dialog-message-reject": "Přetorhnyć",
+ "ooui-dialog-process-error": "Něšto je so nimokuliło",
+ "ooui-dialog-process-dismiss": "Schować",
+ "ooui-dialog-process-retry": "Hišće raz spytać",
+ "ooui-dialog-process-continue": "Dale"
}
diff --git a/resources/lib/oojs-ui/i18n/hu.json b/resources/lib/oojs-ui/i18n/hu.json
index 9117a05e..d50e62da 100644
--- a/resources/lib/oojs-ui/i18n/hu.json
+++ b/resources/lib/oojs-ui/i18n/hu.json
@@ -13,8 +13,11 @@
"ooui-outline-control-move-up": "Elem mozgatása felfelé",
"ooui-outline-control-remove": "Elem eltávolítása",
"ooui-toolbar-more": "Tovább...",
+ "ooui-toolgroup-expand": "Több",
+ "ooui-toolgroup-collapse": "Kevesebb",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Mégse",
"ooui-dialog-process-dismiss": "Elrejt",
- "ooui-dialog-process-retry": "Próbáld újra"
+ "ooui-dialog-process-retry": "Próbáld újra",
+ "ooui-dialog-process-continue": "Folytatás"
}
diff --git a/resources/lib/oojs-ui/i18n/hy.json b/resources/lib/oojs-ui/i18n/hy.json
index ebb28609..2aaf4e46 100644
--- a/resources/lib/oojs-ui/i18n/hy.json
+++ b/resources/lib/oojs-ui/i18n/hy.json
@@ -10,9 +10,12 @@
"ooui-outline-control-move-up": "Բարձրացնել կետը",
"ooui-outline-control-remove": "Հեռացնել տարրը",
"ooui-toolbar-more": "Ավելին",
+ "ooui-toolgroup-expand": "Ավելին",
+ "ooui-toolgroup-collapse": "Պակաս",
"ooui-dialog-message-accept": "Լավ",
"ooui-dialog-message-reject": "Չեղարկել",
"ooui-dialog-process-error": "Ինչ-որ սխալ է տեղի ունեցել",
"ooui-dialog-process-dismiss": "Փակել",
- "ooui-dialog-process-retry": "Կրկին փորձել"
+ "ooui-dialog-process-retry": "Կրկին փորձել",
+ "ooui-dialog-process-continue": "Շարունակել"
}
diff --git a/resources/lib/oojs-ui/i18n/id.json b/resources/lib/oojs-ui/i18n/id.json
index 1710bc66..bd65e71a 100644
--- a/resources/lib/oojs-ui/i18n/id.json
+++ b/resources/lib/oojs-ui/i18n/id.json
@@ -11,8 +11,16 @@
"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"
+ "ooui-outline-control-remove": "Hapus butir",
+ "ooui-toolbar-more": "Lainnya",
+ "ooui-toolgroup-expand": "Selengkapnya",
+ "ooui-toolgroup-collapse": "Secukupnya",
+ "ooui-dialog-message-accept": "Oke",
+ "ooui-dialog-message-reject": "Batal",
+ "ooui-dialog-process-error": "Ada yang tidak beres",
+ "ooui-dialog-process-dismiss": "Tutup",
+ "ooui-dialog-process-retry": "Coba lagi",
+ "ooui-dialog-process-continue": "Lanjutkan"
}
diff --git a/resources/lib/oojs-ui/i18n/ie.json b/resources/lib/oojs-ui/i18n/ie.json
index 4a9f1c46..241cc331 100644
--- a/resources/lib/oojs-ui/i18n/ie.json
+++ b/resources/lib/oojs-ui/i18n/ie.json
@@ -4,7 +4,6 @@
"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"
diff --git a/resources/lib/oojs-ui/i18n/ilo.json b/resources/lib/oojs-ui/i18n/ilo.json
index 81a91ed4..b37beae1 100644
--- a/resources/lib/oojs-ui/i18n/ilo.json
+++ b/resources/lib/oojs-ui/i18n/ilo.json
@@ -8,9 +8,12 @@
"ooui-outline-control-move-up": "Ipangato ti banag",
"ooui-outline-control-remove": "Ikkaten ti banag",
"ooui-toolbar-more": "Adu pay",
+ "ooui-toolgroup-expand": "Adu pay",
+ "ooui-toolgroup-collapse": "Basbassit",
"ooui-dialog-message-accept": "Sige",
"ooui-dialog-message-reject": "Ukasen",
"ooui-dialog-process-error": "Adda madi a napasamak",
"ooui-dialog-process-dismiss": "Pugsayen",
- "ooui-dialog-process-retry": "Padasen manen"
+ "ooui-dialog-process-retry": "Padasen manen",
+ "ooui-dialog-process-continue": "Agtuloy"
}
diff --git a/resources/lib/oojs-ui/i18n/is.json b/resources/lib/oojs-ui/i18n/is.json
index 58fc1b88..3a4e1454 100644
--- a/resources/lib/oojs-ui/i18n/is.json
+++ b/resources/lib/oojs-ui/i18n/is.json
@@ -5,8 +5,16 @@
"Snævar"
]
},
- "ooui-dialog-action-close": "Loka",
"ooui-outline-control-move-down": "Færa atriði niður",
"ooui-outline-control-move-up": "Færa atriði upp",
- "ooui-toolbar-more": "Fleira"
+ "ooui-outline-control-remove": "Fjarlægja atriði",
+ "ooui-toolbar-more": "Fleira",
+ "ooui-toolgroup-expand": "Fleira",
+ "ooui-toolgroup-collapse": "Færra",
+ "ooui-dialog-message-accept": "Í lagi",
+ "ooui-dialog-message-reject": "Hætta við",
+ "ooui-dialog-process-error": "Eitthvað mistókst",
+ "ooui-dialog-process-dismiss": "Loka",
+ "ooui-dialog-process-retry": "Reyna aftur",
+ "ooui-dialog-process-continue": "Halda áfram"
}
diff --git a/resources/lib/oojs-ui/i18n/it.json b/resources/lib/oojs-ui/i18n/it.json
index 3d4e0490..0ff8af8f 100644
--- a/resources/lib/oojs-ui/i18n/it.json
+++ b/resources/lib/oojs-ui/i18n/it.json
@@ -19,9 +19,12 @@
"ooui-outline-control-move-up": "Sposta in alto",
"ooui-outline-control-remove": "Rimuovi elemento",
"ooui-toolbar-more": "Altro",
+ "ooui-toolgroup-expand": "Più",
+ "ooui-toolgroup-collapse": "Meno",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Annulla",
"ooui-dialog-process-error": "Qualcosa è andato storto",
"ooui-dialog-process-dismiss": "Nascondi",
- "ooui-dialog-process-retry": "Riprova"
+ "ooui-dialog-process-retry": "Riprova",
+ "ooui-dialog-process-continue": "Continua"
}
diff --git a/resources/lib/oojs-ui/i18n/ja.json b/resources/lib/oojs-ui/i18n/ja.json
index 2ac8dc19..ec86124e 100644
--- a/resources/lib/oojs-ui/i18n/ja.json
+++ b/resources/lib/oojs-ui/i18n/ja.json
@@ -5,16 +5,20 @@
"Miya",
"Penn Station",
"Shirayuki",
- "Takot"
+ "Takot",
+ "Los688"
]
},
"ooui-outline-control-move-down": "項目を下に移動させる",
"ooui-outline-control-move-up": "項目を上に移動させる",
"ooui-outline-control-remove": "項目を除去",
"ooui-toolbar-more": "その他",
+ "ooui-toolgroup-expand": "続き",
+ "ooui-toolgroup-collapse": "折り畳む",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "キャンセル",
"ooui-dialog-process-error": "エラーが発生しました…",
"ooui-dialog-process-dismiss": "閉じる",
- "ooui-dialog-process-retry": "もう一度お試しください"
+ "ooui-dialog-process-retry": "もう一度お試しください",
+ "ooui-dialog-process-continue": "続行"
}
diff --git a/resources/lib/oojs-ui/i18n/jv.json b/resources/lib/oojs-ui/i18n/jv.json
index 38d35f79..8827af38 100644
--- a/resources/lib/oojs-ui/i18n/jv.json
+++ b/resources/lib/oojs-ui/i18n/jv.json
@@ -6,6 +6,5 @@
"Pras"
]
},
- "ooui-dialog-action-close": "Tutup",
"ooui-outline-control-move-down": "Pindhahaken butir mangandhap"
}
diff --git a/resources/lib/oojs-ui/i18n/ka.json b/resources/lib/oojs-ui/i18n/ka.json
index ef59f1b3..60ef661b 100644
--- a/resources/lib/oojs-ui/i18n/ka.json
+++ b/resources/lib/oojs-ui/i18n/ka.json
@@ -11,8 +11,16 @@
"Tokoko"
]
},
- "ooui-dialog-action-close": "დახურვა",
"ooui-outline-control-move-down": "ელემენტის ქვემოთ გადატანა",
"ooui-outline-control-move-up": "ელემენტის ზემოთ გადატანა",
- "ooui-toolbar-more": "მეტი"
+ "ooui-outline-control-remove": "წაშლა",
+ "ooui-toolbar-more": "მეტი",
+ "ooui-toolgroup-expand": "მეტი",
+ "ooui-toolgroup-collapse": "რამდენიმე",
+ "ooui-dialog-message-accept": "კარგი",
+ "ooui-dialog-message-reject": "გაუქმება",
+ "ooui-dialog-process-error": "მოხდა რაღაც შეცდომა",
+ "ooui-dialog-process-dismiss": "დამალვა",
+ "ooui-dialog-process-retry": "კიდევ სცადეთ",
+ "ooui-dialog-process-continue": "გაგრძელება"
}
diff --git a/resources/lib/oojs-ui/i18n/kk-cyrl.json b/resources/lib/oojs-ui/i18n/kk-cyrl.json
index c1a0f192..1d7317b2 100644
--- a/resources/lib/oojs-ui/i18n/kk-cyrl.json
+++ b/resources/lib/oojs-ui/i18n/kk-cyrl.json
@@ -4,9 +4,16 @@
"Arystanbek"
]
},
- "ooui-dialog-action-close": "Жабу",
"ooui-outline-control-move-down": "Элементті төмен жылжыту",
"ooui-outline-control-move-up": "Элементті жоғары жылжыту",
"ooui-outline-control-remove": "Элементті алып тастау",
- "ooui-toolbar-more": "толығырақ"
+ "ooui-toolbar-more": "толығырақ",
+ "ooui-toolgroup-expand": "Тағы",
+ "ooui-toolgroup-collapse": "Азырақ",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Қажет емес",
+ "ooui-dialog-process-error": "Бірдеңеден қате кетті",
+ "ooui-dialog-process-dismiss": "Тоқтату",
+ "ooui-dialog-process-retry": "Қайта байқап көріңіз",
+ "ooui-dialog-process-continue": "Жалғастыру"
}
diff --git a/resources/lib/oojs-ui/i18n/km.json b/resources/lib/oojs-ui/i18n/km.json
index f7bfca50..c0d72c4f 100644
--- a/resources/lib/oojs-ui/i18n/km.json
+++ b/resources/lib/oojs-ui/i18n/km.json
@@ -4,7 +4,6 @@
"Sovichet"
]
},
- "ooui-dialog-action-close": "បិទ",
"ooui-outline-control-move-down": "រុញ​ទៅ​ក្រោម",
"ooui-outline-control-move-up": "រុញ​ទៅ​លើ",
"ooui-outline-control-remove": "ដក​វត្ថុ​ចេញ",
diff --git a/resources/lib/oojs-ui/i18n/kn.json b/resources/lib/oojs-ui/i18n/kn.json
index 0b89e37d..982a3cdf 100644
--- a/resources/lib/oojs-ui/i18n/kn.json
+++ b/resources/lib/oojs-ui/i18n/kn.json
@@ -2,16 +2,21 @@
"@metadata": {
"authors": [
"Vikassy",
- "Nayvik"
+ "Nayvik",
+ "Omshivaprakash",
+ "Pavanaja"
]
},
- "ooui-outline-control-move-down": "ವಸ್ತು ಕೆಲ್ಗೆ ಸ್ಥಲಾನ್ಥರಿಸು",
- "ooui-outline-control-move-up": "ವಸ್ತು ಮೆಲೆ ಸ್ಥಲಾನ್ಥರಿಸು",
- "ooui-outline-control-remove": "ವಸ್ತು ತೆಗೆ",
- "ooui-toolbar-more": "ಹೆಚ್ಚು",
+ "ooui-outline-control-move-down": "ವಸ್ತುವನ್ನು ಕೆಳಗೆ ಸರಿಸು",
+ "ooui-outline-control-move-up": "ವಸ್ತುವನ್ನು ಮೇಲೆ ಸರಿಸು",
+ "ooui-outline-control-remove": "ವಸ್ತುವನ್ನು ತೆಗೆ",
+ "ooui-toolbar-more": "ಇನ್ನಷ್ಟು",
+ "ooui-toolgroup-expand": "ಇನ್ನಷ್ಟು",
+ "ooui-toolgroup-collapse": "ಕೆಲವೇ ಕೆಲವು",
"ooui-dialog-message-accept": "ಸರಿ",
- "ooui-dialog-message-reject": "ರದ್ದು",
- "ooui-dialog-process-error": "ಎನೋ ಎಡವಟ್ಟಾಗಿದೆ....",
+ "ooui-dialog-message-reject": "ರದ್ದುಮಾಡು",
+ "ooui-dialog-process-error": "ಏನೋ ಎಡವಟ್ಟಾಗಿದೆ....",
"ooui-dialog-process-dismiss": "ತೆಗೆದುಹಾಕು",
- "ooui-dialog-process-retry": "ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"
+ "ooui-dialog-process-retry": "ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ",
+ "ooui-dialog-process-continue": "ಮುಂದುವರೆಸು"
}
diff --git a/resources/lib/oojs-ui/i18n/ko.json b/resources/lib/oojs-ui/i18n/ko.json
index 82d91ab3..196dc2c3 100644
--- a/resources/lib/oojs-ui/i18n/ko.json
+++ b/resources/lib/oojs-ui/i18n/ko.json
@@ -7,13 +7,16 @@
"LFM",
"아라",
"고기랑",
- "Ryuch"
+ "Ryuch",
+ "Revi",
+ "Infinity"
]
},
"ooui-outline-control-move-down": "항목을 아래로 옮기기",
"ooui-outline-control-move-up": "항목을 위로 옮기기",
"ooui-outline-control-remove": "항목 지우기",
"ooui-toolbar-more": "더 보기",
+ "ooui-toolgroup-expand": "더 보기",
"ooui-dialog-message-accept": "확인",
"ooui-dialog-message-reject": "취소",
"ooui-dialog-process-error": "무언가가 잘못되었습니다",
diff --git a/resources/lib/oojs-ui/i18n/krc.json b/resources/lib/oojs-ui/i18n/krc.json
index 18c66e93..ef92e49f 100644
--- a/resources/lib/oojs-ui/i18n/krc.json
+++ b/resources/lib/oojs-ui/i18n/krc.json
@@ -4,9 +4,16 @@
"Iltever"
]
},
- "ooui-dialog-action-close": "Джаб",
"ooui-outline-control-move-down": "Элементни тюбюне кёчюр",
"ooui-outline-control-move-up": "Элементни башына кёчюр",
"ooui-outline-control-remove": "Пунктну кетер",
- "ooui-toolbar-more": "Энтда"
+ "ooui-toolbar-more": "Энтда",
+ "ooui-toolgroup-expand": "Энтда",
+ "ooui-toolgroup-collapse": "Артха",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Ызына ал",
+ "ooui-dialog-process-error": "Не эсе да табсыз кетди",
+ "ooui-dialog-process-dismiss": "Джаб",
+ "ooui-dialog-process-retry": "Энтда сынаб кёр",
+ "ooui-dialog-process-continue": "Бардыр"
}
diff --git a/resources/lib/oojs-ui/i18n/ksh.json b/resources/lib/oojs-ui/i18n/ksh.json
new file mode 100644
index 00000000..c975e825
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/ksh.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "Purodha"
+ ]
+ },
+ "ooui-outline-control-move-down": "Öm eine Plaz noh onge schiehbe",
+ "ooui-outline-control-move-up": "Öm eine Plaz noh bovve schiehbe",
+ "ooui-outline-control-remove": "Dä Plaz läddesch maache → fott domet!",
+ "ooui-toolbar-more": "Mih",
+ "ooui-toolgroup-expand": "Mih",
+ "ooui-toolgroup-collapse": "Winnijer",
+ "ooui-dialog-message-accept": "Lohß Jonn!",
+ "ooui-dialog-message-reject": "Ophühre",
+ "ooui-dialog-process-error": "Öhnsjädd es scheif jejange",
+ "ooui-dialog-process-dismiss": "Maach fott, ha_sch jelässe",
+ "ooui-dialog-process-retry": "Norr_ens versöhke",
+ "ooui-dialog-process-continue": "Wigger maache"
+}
diff --git a/resources/lib/oojs-ui/i18n/ku-latn.json b/resources/lib/oojs-ui/i18n/ku-latn.json
new file mode 100644
index 00000000..be9a8abd
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/ku-latn.json
@@ -0,0 +1,13 @@
+{
+ "@metadata": {
+ "authors": [
+ "George Animal"
+ ]
+ },
+ "ooui-toolgroup-expand": "Bêhtir",
+ "ooui-toolgroup-collapse": "Kêmtir",
+ "ooui-dialog-message-accept": "Baş e",
+ "ooui-dialog-message-reject": "Betal bike",
+ "ooui-dialog-process-retry": "Dîsa hewl bide",
+ "ooui-dialog-process-continue": "Bidomîne"
+}
diff --git a/resources/lib/oojs-ui/i18n/kw.json b/resources/lib/oojs-ui/i18n/kw.json
index c7f28876..a6c6d8ab 100644
--- a/resources/lib/oojs-ui/i18n/kw.json
+++ b/resources/lib/oojs-ui/i18n/kw.json
@@ -5,6 +5,5 @@
"Nrowe",
"Purodha"
]
- },
- "ooui-dialog-action-close": "Degea"
+ }
}
diff --git a/resources/lib/oojs-ui/i18n/ky.json b/resources/lib/oojs-ui/i18n/ky.json
index 7c6b994e..e2b8ab7a 100644
--- a/resources/lib/oojs-ui/i18n/ky.json
+++ b/resources/lib/oojs-ui/i18n/ky.json
@@ -7,6 +7,5 @@
"Tynchtyk Chorotegin",
"Викиней"
]
- },
- "ooui-dialog-action-close": "Жабуу"
+ }
}
diff --git a/resources/lib/oojs-ui/i18n/lb.json b/resources/lib/oojs-ui/i18n/lb.json
index 1cbcb8ad..119d1be9 100644
--- a/resources/lib/oojs-ui/i18n/lb.json
+++ b/resources/lib/oojs-ui/i18n/lb.json
@@ -14,9 +14,12 @@
"ooui-outline-control-move-up": "Element erop réckelen",
"ooui-outline-control-remove": "Element ewechhuelen",
"ooui-toolbar-more": "Méi",
+ "ooui-toolgroup-expand": "Méi",
+ "ooui-toolgroup-collapse": "Manner",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Ofbriechen",
"ooui-dialog-process-error": "Et ass eppes schif gaang",
"ooui-dialog-process-dismiss": "Verwerfen",
- "ooui-dialog-process-retry": "Nach eng Kéier probéieren"
+ "ooui-dialog-process-retry": "Nach eng Kéier probéieren",
+ "ooui-dialog-process-continue": "Virufueren"
}
diff --git a/resources/lib/oojs-ui/i18n/lmo.json b/resources/lib/oojs-ui/i18n/lmo.json
index 3156e84e..87309db0 100644
--- a/resources/lib/oojs-ui/i18n/lmo.json
+++ b/resources/lib/oojs-ui/i18n/lmo.json
@@ -4,7 +4,6 @@
"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ò"
diff --git a/resources/lib/oojs-ui/i18n/lt.json b/resources/lib/oojs-ui/i18n/lt.json
index e2957044..ecd06a8a 100644
--- a/resources/lib/oojs-ui/i18n/lt.json
+++ b/resources/lib/oojs-ui/i18n/lt.json
@@ -6,6 +6,5 @@
"Mantak111"
]
},
- "ooui-dialog-action-close": "Uždaryti",
"ooui-outline-control-remove": "Šalinti elementus"
}
diff --git a/resources/lib/oojs-ui/i18n/lv.json b/resources/lib/oojs-ui/i18n/lv.json
index 32fc9fe5..9ff787ac 100644
--- a/resources/lib/oojs-ui/i18n/lv.json
+++ b/resources/lib/oojs-ui/i18n/lv.json
@@ -11,7 +11,11 @@
"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",
+ "ooui-toolgroup-expand": "Vairāk",
+ "ooui-toolgroup-collapse": "Mazāk",
"ooui-dialog-message-accept": "Labi",
"ooui-dialog-message-reject": "Atcelt",
- "ooui-dialog-process-retry": "Mēģināt vēlreiz"
+ "ooui-dialog-process-error": "Kaut kas nogāja greizi",
+ "ooui-dialog-process-retry": "Mēģināt vēlreiz",
+ "ooui-dialog-process-continue": "Turpināt"
}
diff --git a/resources/lib/oojs-ui/i18n/lzh.json b/resources/lib/oojs-ui/i18n/lzh.json
index f296c3a4..2b3ad53c 100644
--- a/resources/lib/oojs-ui/i18n/lzh.json
+++ b/resources/lib/oojs-ui/i18n/lzh.json
@@ -4,5 +4,5 @@
"Joe young yu"
]
},
- "ooui-dialog-confirm-default-ok": "可"
+ "ooui-dialog-message-accept": "可"
}
diff --git a/resources/lib/oojs-ui/i18n/mg.json b/resources/lib/oojs-ui/i18n/mg.json
index 2f276149..af97d171 100644
--- a/resources/lib/oojs-ui/i18n/mg.json
+++ b/resources/lib/oojs-ui/i18n/mg.json
@@ -3,6 +3,5 @@
"authors": [
"Jagwar"
]
- },
- "ooui-dialog-action-close": "Hidiana"
+ }
}
diff --git a/resources/lib/oojs-ui/i18n/min.json b/resources/lib/oojs-ui/i18n/min.json
index 6dfe34a1..b8790d31 100644
--- a/resources/lib/oojs-ui/i18n/min.json
+++ b/resources/lib/oojs-ui/i18n/min.json
@@ -5,13 +5,10 @@
"Jagwar"
]
},
- "ooui-dialog-action-close": "Tutuik",
"ooui-outline-control-move-down": "Pindahan ko ka bawah",
"ooui-outline-control-move-up": "Pindahan ko ka ateh",
"ooui-outline-control-remove": "Hapuih ko",
"ooui-toolbar-more": "Lainnyo",
- "ooui-dialog-confirm-title": "Pastian",
- "ooui-dialog-confirm-default-prompt": "Yakin?",
- "ooui-dialog-confirm-default-ok": "Yo",
- "ooui-dialog-confirm-default-cancel": "Batal"
+ "ooui-dialog-message-accept": "Yo",
+ "ooui-dialog-message-reject": "Batal"
}
diff --git a/resources/lib/oojs-ui/i18n/mk.json b/resources/lib/oojs-ui/i18n/mk.json
index d628034b..7962336c 100644
--- a/resources/lib/oojs-ui/i18n/mk.json
+++ b/resources/lib/oojs-ui/i18n/mk.json
@@ -10,9 +10,12 @@
"ooui-outline-control-move-up": "Помести нагоре",
"ooui-outline-control-remove": "Отстрани ставка",
"ooui-toolbar-more": "Повеќе",
+ "ooui-toolgroup-expand": "Повеќе",
+ "ooui-toolgroup-collapse": "Помалку",
"ooui-dialog-message-accept": "ОК",
"ooui-dialog-message-reject": "Откажи",
"ooui-dialog-process-error": "Нешто не е во ред",
"ooui-dialog-process-dismiss": "Тргни",
- "ooui-dialog-process-retry": "Обиди се пак"
+ "ooui-dialog-process-retry": "Обиди се пак",
+ "ooui-dialog-process-continue": "Продолжи"
}
diff --git a/resources/lib/oojs-ui/i18n/ml.json b/resources/lib/oojs-ui/i18n/ml.json
index 48b05f58..0ce0c3fd 100644
--- a/resources/lib/oojs-ui/i18n/ml.json
+++ b/resources/lib/oojs-ui/i18n/ml.json
@@ -7,7 +7,6 @@
"Vssun"
]
},
- "ooui-dialog-action-close": "അടയ്ക്കുക",
"ooui-outline-control-move-down": "ഇനം താഴേയ്ക്ക് മാറ്റുക",
"ooui-outline-control-move-up": "ഇനം മുകളിലേയ്ക്ക് മാറ്റുക",
"ooui-toolbar-more": "കൂടുതൽ"
diff --git a/resources/lib/oojs-ui/i18n/mr.json b/resources/lib/oojs-ui/i18n/mr.json
index 618b5dc0..70061907 100644
--- a/resources/lib/oojs-ui/i18n/mr.json
+++ b/resources/lib/oojs-ui/i18n/mr.json
@@ -9,7 +9,6 @@
"संतोष दहिवळ"
]
},
- "ooui-dialog-action-close": "बंद करा",
"ooui-outline-control-move-down": "घटक (आयटम) खाली सरकवा",
"ooui-outline-control-move-up": "घटक (आयटम) वर सरकवा",
"ooui-toolbar-more": "अधिक"
diff --git a/resources/lib/oojs-ui/i18n/nap.json b/resources/lib/oojs-ui/i18n/nap.json
index 2cee4137..91660373 100644
--- a/resources/lib/oojs-ui/i18n/nap.json
+++ b/resources/lib/oojs-ui/i18n/nap.json
@@ -6,6 +6,5 @@
"PiRSquared17"
]
},
- "ooui-dialog-action-close": "Chiure",
"ooui-toolbar-more": "Atro"
}
diff --git a/resources/lib/oojs-ui/i18n/nb.json b/resources/lib/oojs-ui/i18n/nb.json
index 3fe75e3f..9e773924 100644
--- a/resources/lib/oojs-ui/i18n/nb.json
+++ b/resources/lib/oojs-ui/i18n/nb.json
@@ -6,16 +6,20 @@
"Jeblad",
"Laaknor",
"Njardarlogar",
- "Jdforrester"
+ "Jdforrester",
+ "Apple farmer"
]
},
"ooui-outline-control-move-down": "Flytt ned",
"ooui-outline-control-move-up": "Flytt opp",
"ooui-outline-control-remove": "Fjern element",
"ooui-toolbar-more": "Mer",
+ "ooui-toolgroup-expand": "Mer",
+ "ooui-toolgroup-collapse": "Færre",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Avbryt",
"ooui-dialog-process-error": "Noe gikk galt",
"ooui-dialog-process-dismiss": "Lukk",
- "ooui-dialog-process-retry": "Prøv igjen"
+ "ooui-dialog-process-retry": "Prøv igjen",
+ "ooui-dialog-process-continue": "Fortsett"
}
diff --git a/resources/lib/oojs-ui/i18n/nds-nl.json b/resources/lib/oojs-ui/i18n/nds-nl.json
index e8f0c83d..d3db318b 100644
--- a/resources/lib/oojs-ui/i18n/nds-nl.json
+++ b/resources/lib/oojs-ui/i18n/nds-nl.json
@@ -4,7 +4,16 @@
"Servien"
]
},
- "ooui-dialog-action-close": "Sluten",
"ooui-outline-control-move-down": "Onderwarp ummeneer zetten",
- "ooui-outline-control-move-up": "Onderwarp umhoge zetten"
+ "ooui-outline-control-move-up": "Onderwarp umhoge zetten",
+ "ooui-outline-control-remove": "Element vortdoon",
+ "ooui-toolbar-more": "Meer",
+ "ooui-toolgroup-expand": "Meer",
+ "ooui-toolgroup-collapse": "Minder",
+ "ooui-dialog-message-accept": "Okee",
+ "ooui-dialog-message-reject": "Aofbreken",
+ "ooui-dialog-process-error": "Der gung iets fout",
+ "ooui-dialog-process-dismiss": "Sluten",
+ "ooui-dialog-process-retry": "Opniej proberen",
+ "ooui-dialog-process-continue": "Deurgaon"
}
diff --git a/resources/lib/oojs-ui/i18n/nds.json b/resources/lib/oojs-ui/i18n/nds.json
index c5d16ba0..1e5b83dd 100644
--- a/resources/lib/oojs-ui/i18n/nds.json
+++ b/resources/lib/oojs-ui/i18n/nds.json
@@ -4,7 +4,6 @@
"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"
diff --git a/resources/lib/oojs-ui/i18n/ne.json b/resources/lib/oojs-ui/i18n/ne.json
index da4b829d..4ca5ab72 100644
--- a/resources/lib/oojs-ui/i18n/ne.json
+++ b/resources/lib/oojs-ui/i18n/ne.json
@@ -6,13 +6,15 @@
"Ganesh Paudel"
]
},
- "ooui-dialog-action-close": "बन्द गर्ने",
"ooui-outline-control-move-down": "वस्तुलाई तल सार्ने",
"ooui-outline-control-move-up": "वस्तुलाई माथि सार्ने",
"ooui-outline-control-remove": "वस्तुलाई हटाउने",
"ooui-toolbar-more": "थप",
- "ooui-dialog-confirm-title": "निश्चित गर्ने",
- "ooui-dialog-confirm-default-prompt": "निश्चित हुनुहुन्छ ?",
- "ooui-dialog-confirm-default-ok": "हुन्छ",
- "ooui-dialog-confirm-default-cancel": "रद्द गर्ने"
+ "ooui-toolgroup-expand": "थप",
+ "ooui-toolgroup-collapse": "कम",
+ "ooui-dialog-message-accept": "हुन्छ",
+ "ooui-dialog-message-reject": "रद्द गर्ने",
+ "ooui-dialog-process-dismiss": "खारेज गर्ने",
+ "ooui-dialog-process-retry": "पुन प्रयास गर्नुहोस",
+ "ooui-dialog-process-continue": "जारी राख्ने"
}
diff --git a/resources/lib/oojs-ui/i18n/nl.json b/resources/lib/oojs-ui/i18n/nl.json
index a7b4c084..7c7b1767 100644
--- a/resources/lib/oojs-ui/i18n/nl.json
+++ b/resources/lib/oojs-ui/i18n/nl.json
@@ -24,9 +24,12 @@
"ooui-outline-control-move-up": "Item omhoog verplaatsen",
"ooui-outline-control-remove": "Item verwijderen",
"ooui-toolbar-more": "Meer",
+ "ooui-toolgroup-expand": "Meer",
+ "ooui-toolgroup-collapse": "Minder",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Annuleren",
"ooui-dialog-process-error": "Er is iets misgegaan",
"ooui-dialog-process-dismiss": "Sluiten",
- "ooui-dialog-process-retry": "Opnieuw proberen"
+ "ooui-dialog-process-retry": "Opnieuw proberen",
+ "ooui-dialog-process-continue": "Doorgaan"
}
diff --git a/resources/lib/oojs-ui/i18n/nn.json b/resources/lib/oojs-ui/i18n/nn.json
index 07a40b17..943e6adc 100644
--- a/resources/lib/oojs-ui/i18n/nn.json
+++ b/resources/lib/oojs-ui/i18n/nn.json
@@ -5,7 +5,6 @@
"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"
diff --git a/resources/lib/oojs-ui/i18n/oc.json b/resources/lib/oojs-ui/i18n/oc.json
index a7f43a3e..4d35b6c9 100644
--- a/resources/lib/oojs-ui/i18n/oc.json
+++ b/resources/lib/oojs-ui/i18n/oc.json
@@ -5,12 +5,9 @@
"Gloria sah"
]
},
- "ooui-dialog-action-close": "Tampar",
"ooui-outline-control-move-down": "Far davalar l’element",
"ooui-outline-control-move-up": "Far montar l’element",
"ooui-outline-control-remove": "Suprimir l’element",
"ooui-toolbar-more": "Mai",
- "ooui-dialog-confirm-title": "Confirmar",
- "ooui-dialog-confirm-default-prompt": "Sètz segur ?",
- "ooui-dialog-confirm-default-cancel": "Anullar"
+ "ooui-dialog-message-reject": "Anullar"
}
diff --git a/resources/lib/oojs-ui/i18n/om.json b/resources/lib/oojs-ui/i18n/om.json
index c62782ef..ecf95971 100644
--- a/resources/lib/oojs-ui/i18n/om.json
+++ b/resources/lib/oojs-ui/i18n/om.json
@@ -9,9 +9,12 @@
"ooui-outline-control-move-up": "Ol baasi",
"ooui-outline-control-remove": "Balleessi",
"ooui-toolbar-more": "Dabalata",
+ "ooui-toolgroup-expand": "Dabalata",
+ "ooui-toolgroup-collapse": "Xiqqaa",
"ooui-dialog-message-accept": "Tole",
"ooui-dialog-message-reject": "Dhiisi",
"ooui-dialog-process-error": "Dogoggorri wayii ummameera",
"ooui-dialog-process-dismiss": "Didi",
- "ooui-dialog-process-retry": "Itti deebi'ii yaali"
+ "ooui-dialog-process-retry": "Itti deebi'ii yaali",
+ "ooui-dialog-process-continue": "Itti fufi"
}
diff --git a/resources/lib/oojs-ui/i18n/or.json b/resources/lib/oojs-ui/i18n/or.json
index a7083ae1..dde49bf1 100644
--- a/resources/lib/oojs-ui/i18n/or.json
+++ b/resources/lib/oojs-ui/i18n/or.json
@@ -6,5 +6,16 @@
"ଶିତିକଣ୍ଠ ଦାଶ"
]
},
- "ooui-dialog-action-close": "ବନ୍ଦ କରିବେ"
+ "ooui-outline-control-move-down": "ବସ୍ତୁଟିକୁ ତଳକୁ ଘୁଞ୍ଚାନ୍ତୁ",
+ "ooui-outline-control-move-up": "ବସ୍ତୁଟିକୁ ଉପରକୁ ଘୁଞ୍ଚାନ୍ତୁ",
+ "ooui-outline-control-remove": "ବସ୍ତୁଟିକୁ ଲିଭାନ୍ତୁ",
+ "ooui-toolbar-more": "ଅଧିକ",
+ "ooui-toolgroup-expand": "ଅଧିକ",
+ "ooui-toolgroup-collapse": "ଅଳ୍ପ",
+ "ooui-dialog-message-accept": "ହେଉ",
+ "ooui-dialog-message-reject": "ନାକଚ",
+ "ooui-dialog-process-error": "ଅସୁବିଧାଟିଏ ଘଟିଲା",
+ "ooui-dialog-process-dismiss": "ଖାରଜ",
+ "ooui-dialog-process-retry": "ଆଉ ଥରେ ଚେଷ୍ଟା କରନ୍ତୁ",
+ "ooui-dialog-process-continue": "ଚାଲୁରଖିବେ"
}
diff --git a/resources/lib/oojs-ui/i18n/pa.json b/resources/lib/oojs-ui/i18n/pa.json
index 8f75286d..8c7a1e7c 100644
--- a/resources/lib/oojs-ui/i18n/pa.json
+++ b/resources/lib/oojs-ui/i18n/pa.json
@@ -4,8 +4,19 @@
"Amikeco",
"Babanwalia",
"Bouron",
- "Nasir8891"
+ "Nasir8891",
+ "Satdeep gill"
]
},
- "ooui-dialog-action-close": "বন্ধ"
+ "ooui-outline-control-move-down": "ਨੀਚੇ ਲੈਕੇ ਜਾਓ",
+ "ooui-outline-control-move-up": "ਉੱਤੇ ਲੈਕੇ ਜਾਓ",
+ "ooui-toolbar-more": "ਹੋਰ",
+ "ooui-toolgroup-expand": "ਹੋਰ",
+ "ooui-toolgroup-collapse": "ਥੋੜੇ",
+ "ooui-dialog-message-accept": "ਠੀਕ ਹੈ",
+ "ooui-dialog-message-reject": "ਰੱਦ ਕਰੋ",
+ "ooui-dialog-process-error": "ਕੁਝ ਗਲਤ ਹੋ ਗਿਆ",
+ "ooui-dialog-process-dismiss": "ਰੱਦ ਕਰੋ",
+ "ooui-dialog-process-retry": "ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ",
+ "ooui-dialog-process-continue": "ਜਾਰੀ ਰੱਖੋ"
}
diff --git a/resources/lib/oojs-ui/i18n/pfl.json b/resources/lib/oojs-ui/i18n/pfl.json
index b51f70dc..02d08426 100644
--- a/resources/lib/oojs-ui/i18n/pfl.json
+++ b/resources/lib/oojs-ui/i18n/pfl.json
@@ -4,12 +4,10 @@
"Manuae"
]
},
- "ooui-dialog-action-close": "Schließe",
"ooui-outline-control-move-down": "Bweeschs nunna",
"ooui-outline-control-move-up": "Bweeschs nuff",
"ooui-outline-control-remove": "Leschs",
"ooui-toolbar-more": "Mea",
- "ooui-dialog-confirm-default-prompt": "Bischda sischa?",
- "ooui-dialog-confirm-default-ok": "OK",
- "ooui-dialog-confirm-default-cancel": "Abbresche"
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Abbresche"
}
diff --git a/resources/lib/oojs-ui/i18n/pl.json b/resources/lib/oojs-ui/i18n/pl.json
index 7978673b..fbd0c8cc 100644
--- a/resources/lib/oojs-ui/i18n/pl.json
+++ b/resources/lib/oojs-ui/i18n/pl.json
@@ -23,9 +23,12 @@
"ooui-outline-control-move-up": "Przenieś wyżej",
"ooui-outline-control-remove": "Usuń element",
"ooui-toolbar-more": "Więcej",
+ "ooui-toolgroup-expand": "Więcej",
+ "ooui-toolgroup-collapse": "Mniej",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Anuluj",
"ooui-dialog-process-error": "Coś poszło nie tak",
"ooui-dialog-process-dismiss": "Ukryj",
- "ooui-dialog-process-retry": "Spróbuj ponownie"
+ "ooui-dialog-process-retry": "Spróbuj ponownie",
+ "ooui-dialog-process-continue": "Kontynuuj"
}
diff --git a/resources/lib/oojs-ui/i18n/pms.json b/resources/lib/oojs-ui/i18n/pms.json
index a202a02d..b8fd3a58 100644
--- a/resources/lib/oojs-ui/i18n/pms.json
+++ b/resources/lib/oojs-ui/i18n/pms.json
@@ -6,7 +6,6 @@
"පසිඳු කාවින්ද"
]
},
- "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"
diff --git a/resources/lib/oojs-ui/i18n/ps.json b/resources/lib/oojs-ui/i18n/ps.json
index 06d3b879..ebffe539 100644
--- a/resources/lib/oojs-ui/i18n/ps.json
+++ b/resources/lib/oojs-ui/i18n/ps.json
@@ -4,8 +4,15 @@
"Ahmed-Najib-Biabani-Ibrahimkhel"
]
},
- "ooui-dialog-action-close": "تړل",
"ooui-outline-control-move-down": "توکی ښکته راوړل",
"ooui-outline-control-move-up": "توکی پورته راوړل",
- "ooui-toolbar-more": "نور"
+ "ooui-outline-control-remove": "توکی غورځول",
+ "ooui-toolbar-more": "نور",
+ "ooui-toolgroup-expand": "نور",
+ "ooui-toolgroup-collapse": "لږ تر لږ",
+ "ooui-dialog-message-accept": "ښه",
+ "ooui-dialog-message-reject": "ناگارل",
+ "ooui-dialog-process-error": "يوه ستونزه رامنځ ته شوه",
+ "ooui-dialog-process-dismiss": "تړل",
+ "ooui-dialog-process-retry": "بيا هڅه"
}
diff --git a/resources/lib/oojs-ui/i18n/pt-br.json b/resources/lib/oojs-ui/i18n/pt-br.json
index a8cced8a..94ea0895 100644
--- a/resources/lib/oojs-ui/i18n/pt-br.json
+++ b/resources/lib/oojs-ui/i18n/pt-br.json
@@ -12,7 +12,6 @@
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"
diff --git a/resources/lib/oojs-ui/i18n/pt.json b/resources/lib/oojs-ui/i18n/pt.json
index 5cb3e3d8..7b3176fb 100644
--- a/resources/lib/oojs-ui/i18n/pt.json
+++ b/resources/lib/oojs-ui/i18n/pt.json
@@ -17,9 +17,12 @@
"ooui-outline-control-move-up": "Mover item para cima",
"ooui-outline-control-remove": "Remover elemento",
"ooui-toolbar-more": "Mais",
+ "ooui-toolgroup-expand": "Mais",
+ "ooui-toolgroup-collapse": "Menos",
"ooui-dialog-message-accept": "Aceitar",
"ooui-dialog-message-reject": "Cancelar",
"ooui-dialog-process-error": "Algo correu mal",
"ooui-dialog-process-dismiss": "Ignorar",
- "ooui-dialog-process-retry": "Tentar novamente"
+ "ooui-dialog-process-retry": "Tentar novamente",
+ "ooui-dialog-process-continue": "Continuar"
}
diff --git a/resources/lib/oojs-ui/i18n/qqq.json b/resources/lib/oojs-ui/i18n/qqq.json
index 9b3bb605..c1b794ab 100644
--- a/resources/lib/oojs-ui/i18n/qqq.json
+++ b/resources/lib/oojs-ui/i18n/qqq.json
@@ -24,9 +24,12 @@
"ooui-outline-control-move-up": "Tool tip for a button that moves items in a list up one place",
"ooui-outline-control-remove": "Tool tip for a button that removes items from a list.\n{{Identical|Remove item}}",
"ooui-toolbar-more": "Label for the toolbar group that contains a list of all other available tools.\n{{Identical|More}}",
+ "ooui-toolgroup-expand": "Label for the fake tool that expands the full list of tools in a toolbar group.\n\nSee also:\n* {{msg-mw|Ooui-toolgroup-collapse}}\n{{Identical|More}}",
+ "ooui-toolgroup-collapse": "Label for the fake tool that collapses the full list of tools in a toolbar group.\n\nSee also:\n* {{msg-mw|Ooui-toolgroup-expand}}\n{{Identical|Fewer}}",
"ooui-dialog-message-accept": "Default label for the accept button of a message dialog\n{{Identical|OK}}",
"ooui-dialog-message-reject": "Default label for the reject button of a message dialog\n{{Identical|Cancel}}",
"ooui-dialog-process-error": "Title for process dialog error description",
"ooui-dialog-process-dismiss": "Label for process dialog dismiss error button, visible when describing errors\n{{Identical|Dismiss}}",
- "ooui-dialog-process-retry": "Label for process dialog retry action button, visible when describing recoverable errors\n{{Identical|Try again}}"
+ "ooui-dialog-process-retry": "Label for process dialog retry action button, visible when describing recoverable errors\n{{Identical|Try again}}",
+ "ooui-dialog-process-continue": "Label for process dialog retry action button, visible when describing only warnings\n{{Identical|Continue}}"
}
diff --git a/resources/lib/oojs-ui/i18n/qu.json b/resources/lib/oojs-ui/i18n/qu.json
index 5141f342..cb0b2c33 100644
--- a/resources/lib/oojs-ui/i18n/qu.json
+++ b/resources/lib/oojs-ui/i18n/qu.json
@@ -5,7 +5,6 @@
"Jduranboger"
]
},
- "ooui-dialog-action-close": "Wichq'ay",
"ooui-outline-control-move-down": "Qallawata uraykuchiy",
"ooui-outline-control-move-up": "Qallawata huqariy",
"ooui-outline-control-remove": "P'anqa sutikunata qichuy",
diff --git a/resources/lib/oojs-ui/i18n/ro.json b/resources/lib/oojs-ui/i18n/ro.json
index 06e0f1de..258f3e74 100644
--- a/resources/lib/oojs-ui/i18n/ro.json
+++ b/resources/lib/oojs-ui/i18n/ro.json
@@ -12,9 +12,12 @@
"ooui-outline-control-move-up": "Mută elementul mai sus",
"ooui-outline-control-remove": "Elimină elementul",
"ooui-toolbar-more": "Mai mult",
+ "ooui-toolgroup-expand": "Mai multe",
+ "ooui-toolgroup-collapse": "Mai puține",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Revocare",
"ooui-dialog-process-error": "Ceva nu a funcționat",
"ooui-dialog-process-dismiss": "Renunțare",
- "ooui-dialog-process-retry": "Reîncearcă"
+ "ooui-dialog-process-retry": "Reîncearcă",
+ "ooui-dialog-process-continue": "Continuă"
}
diff --git a/resources/lib/oojs-ui/i18n/roa-tara.json b/resources/lib/oojs-ui/i18n/roa-tara.json
index 11427ec3..f6f422a2 100644
--- a/resources/lib/oojs-ui/i18n/roa-tara.json
+++ b/resources/lib/oojs-ui/i18n/roa-tara.json
@@ -4,8 +4,16 @@
"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ù"
+ "ooui-outline-control-remove": "Live 'a vôsce",
+ "ooui-toolbar-more": "De cchiù",
+ "ooui-toolgroup-expand": "De cchiù",
+ "ooui-toolgroup-collapse": "De mene",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Annulle",
+ "ooui-dialog-process-error": "Quacche cose ha sciute stuèrte",
+ "ooui-dialog-process-dismiss": "Scitte",
+ "ooui-dialog-process-retry": "Pruève arrete",
+ "ooui-dialog-process-continue": "Condinue"
}
diff --git a/resources/lib/oojs-ui/i18n/ru.json b/resources/lib/oojs-ui/i18n/ru.json
index efd10627..129dd6a2 100644
--- a/resources/lib/oojs-ui/i18n/ru.json
+++ b/resources/lib/oojs-ui/i18n/ru.json
@@ -15,16 +15,20 @@
"Putnik",
"Sunpriat",
"Yury Katkov",
- "Умар"
+ "Умар",
+ "Камалист"
]
},
"ooui-outline-control-move-down": "Переместить элемент вниз",
"ooui-outline-control-move-up": "Переместить элемент вверх",
"ooui-outline-control-remove": "Удалить пункт",
"ooui-toolbar-more": "Ещё",
+ "ooui-toolgroup-expand": "Больше",
+ "ooui-toolgroup-collapse": "Меньше",
"ooui-dialog-message-accept": "ОК",
"ooui-dialog-message-reject": "Отмена",
"ooui-dialog-process-error": "Что-то пошло не так",
"ooui-dialog-process-dismiss": "Закрыть",
- "ooui-dialog-process-retry": "Попробовать ещё раз"
+ "ooui-dialog-process-retry": "Попробовать ещё раз",
+ "ooui-dialog-process-continue": "Продолжить"
}
diff --git a/resources/lib/oojs-ui/i18n/sah.json b/resources/lib/oojs-ui/i18n/sah.json
index 82d76a64..85a94cd5 100644
--- a/resources/lib/oojs-ui/i18n/sah.json
+++ b/resources/lib/oojs-ui/i18n/sah.json
@@ -4,6 +4,5 @@
"Gazeb",
"HalanTul"
]
- },
- "ooui-dialog-action-close": "Сап"
+ }
}
diff --git a/resources/lib/oojs-ui/i18n/scn.json b/resources/lib/oojs-ui/i18n/scn.json
index a063cc8e..22a212f9 100644
--- a/resources/lib/oojs-ui/i18n/scn.json
+++ b/resources/lib/oojs-ui/i18n/scn.json
@@ -7,9 +7,7 @@
"Gloria sah"
]
},
- "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",
- "ooui-dialog-confirm-title": "Cunferma"
+ "ooui-toolbar-more": "Àutri cosi"
}
diff --git a/resources/lib/oojs-ui/i18n/sco.json b/resources/lib/oojs-ui/i18n/sco.json
index 085f908a..0a26a5c8 100644
--- a/resources/lib/oojs-ui/i18n/sco.json
+++ b/resources/lib/oojs-ui/i18n/sco.json
@@ -4,7 +4,6 @@
"John Reid"
]
},
- "ooui-dialog-action-close": "Claise",
"ooui-outline-control-move-down": "Muiv eetem doon",
"ooui-outline-control-move-up": "Muiv eetem up",
"ooui-outline-control-remove": "Remuiv eetem",
diff --git a/resources/lib/oojs-ui/i18n/sh.json b/resources/lib/oojs-ui/i18n/sh.json
index ab9f9fd6..b40fa04e 100644
--- a/resources/lib/oojs-ui/i18n/sh.json
+++ b/resources/lib/oojs-ui/i18n/sh.json
@@ -4,7 +4,6 @@
"OC Ripper"
]
},
- "ooui-dialog-action-close": "Zatvori",
"ooui-outline-control-move-down": "Pomakni stavku dolje",
"ooui-outline-control-move-up": "Pomakni stavku gore"
}
diff --git a/resources/lib/oojs-ui/i18n/si.json b/resources/lib/oojs-ui/i18n/si.json
index b5c0b692..5988773b 100644
--- a/resources/lib/oojs-ui/i18n/si.json
+++ b/resources/lib/oojs-ui/i18n/si.json
@@ -6,7 +6,6 @@
"ශ්වෙත"
]
},
- "ooui-dialog-action-close": "නිමවන්න",
"ooui-outline-control-move-down": "අයිතමය පහලටදමන්න",
"ooui-outline-control-move-up": "අයිතමය ඉහලටදමන්න"
}
diff --git a/resources/lib/oojs-ui/i18n/sk.json b/resources/lib/oojs-ui/i18n/sk.json
index 07d98286..c8246da9 100644
--- a/resources/lib/oojs-ui/i18n/sk.json
+++ b/resources/lib/oojs-ui/i18n/sk.json
@@ -5,8 +5,8 @@
"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-outline-control-remove": "Odstrániť položku",
"ooui-toolbar-more": "Viac"
}
diff --git a/resources/lib/oojs-ui/i18n/sl.json b/resources/lib/oojs-ui/i18n/sl.json
index 5737548e..a40728ad 100644
--- a/resources/lib/oojs-ui/i18n/sl.json
+++ b/resources/lib/oojs-ui/i18n/sl.json
@@ -11,9 +11,12 @@
"ooui-outline-control-move-up": "Prestavi predmet višje",
"ooui-outline-control-remove": "Odstrani vnos",
"ooui-toolbar-more": "Več",
+ "ooui-toolgroup-expand": "Več",
+ "ooui-toolgroup-collapse": "Manj",
"ooui-dialog-message-accept": "V redu",
"ooui-dialog-message-reject": "Prekliči",
"ooui-dialog-process-error": "Nekaj je šlo narobe",
"ooui-dialog-process-dismiss": "Skrij",
- "ooui-dialog-process-retry": "Poskusi znova"
+ "ooui-dialog-process-retry": "Poskusi znova",
+ "ooui-dialog-process-continue": "Nadaljuj"
}
diff --git a/resources/lib/oojs-ui/i18n/sr-ec.json b/resources/lib/oojs-ui/i18n/sr-ec.json
index d6533569..c827554e 100644
--- a/resources/lib/oojs-ui/i18n/sr-ec.json
+++ b/resources/lib/oojs-ui/i18n/sr-ec.json
@@ -10,9 +10,12 @@
"ooui-outline-control-move-up": "Премести ставку на горе",
"ooui-outline-control-remove": "Уклони ставку",
"ooui-toolbar-more": "Више",
+ "ooui-toolgroup-expand": "Више",
+ "ooui-toolgroup-collapse": "Мање",
"ooui-dialog-message-accept": "У реду",
"ooui-dialog-message-reject": "Откажи",
"ooui-dialog-process-error": "Нешто је пошло наопако",
"ooui-dialog-process-dismiss": "Одбаци",
- "ooui-dialog-process-retry": "Покушај поново"
+ "ooui-dialog-process-retry": "Покушај поново",
+ "ooui-dialog-process-continue": "Настави"
}
diff --git a/resources/lib/oojs-ui/i18n/sr-el.json b/resources/lib/oojs-ui/i18n/sr-el.json
index 889b0f68..704a1860 100644
--- a/resources/lib/oojs-ui/i18n/sr-el.json
+++ b/resources/lib/oojs-ui/i18n/sr-el.json
@@ -4,10 +4,16 @@
"Milicevic01"
]
},
- "ooui-dialog-action-close": "Zatvori",
"ooui-outline-control-move-down": "Premesti stavku na dole",
"ooui-outline-control-move-up": "Premesti stavku na gore",
"ooui-outline-control-remove": "Ukloni stavku",
"ooui-toolbar-more": "Više",
- "ooui-dialog-confirm-default-prompt": "Jeste li sigurni?"
+ "ooui-toolgroup-expand": "Više",
+ "ooui-toolgroup-collapse": "Manje",
+ "ooui-dialog-message-accept": "U redu",
+ "ooui-dialog-message-reject": "Otkaži",
+ "ooui-dialog-process-error": "Nešto je pošlo naopako",
+ "ooui-dialog-process-dismiss": "Odbaci",
+ "ooui-dialog-process-retry": "Pokušaj ponovo",
+ "ooui-dialog-process-continue": "Nastavi"
}
diff --git a/resources/lib/oojs-ui/i18n/sv.json b/resources/lib/oojs-ui/i18n/sv.json
index 40305d0a..d499427c 100644
--- a/resources/lib/oojs-ui/i18n/sv.json
+++ b/resources/lib/oojs-ui/i18n/sv.json
@@ -18,9 +18,12 @@
"ooui-outline-control-move-up": "Flytta upp objekt",
"ooui-outline-control-remove": "Ta bort objekt",
"ooui-toolbar-more": "Mer",
+ "ooui-toolgroup-expand": "Fler",
+ "ooui-toolgroup-collapse": "Färre",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Avbryt",
"ooui-dialog-process-error": "Något gick fel",
"ooui-dialog-process-dismiss": "Stäng",
- "ooui-dialog-process-retry": "Försök igen"
+ "ooui-dialog-process-retry": "Försök igen",
+ "ooui-dialog-process-continue": "Fortsätt"
}
diff --git a/resources/lib/oojs-ui/i18n/ta.json b/resources/lib/oojs-ui/i18n/ta.json
index dd8294fe..122d4a27 100644
--- a/resources/lib/oojs-ui/i18n/ta.json
+++ b/resources/lib/oojs-ui/i18n/ta.json
@@ -4,8 +4,10 @@
"Jayarathina",
"Sank",
"Shanmugamp7",
- "மதனாஹரன்"
+ "மதனாஹரன்",
+ "ElangoRamanujam"
]
},
- "ooui-dialog-action-close": "மூடுக"
+ "ooui-toolgroup-expand": "மேலும்",
+ "ooui-dialog-process-continue": "தொடரவும்"
}
diff --git a/resources/lib/oojs-ui/i18n/te.json b/resources/lib/oojs-ui/i18n/te.json
index f220fa3f..d4868706 100644
--- a/resources/lib/oojs-ui/i18n/te.json
+++ b/resources/lib/oojs-ui/i18n/te.json
@@ -9,6 +9,5 @@
"Visdaviva",
"மதனாஹரன்"
]
- },
- "ooui-dialog-action-close": "మూయి"
+ }
}
diff --git a/resources/lib/oojs-ui/i18n/tg-cyrl.json b/resources/lib/oojs-ui/i18n/tg-cyrl.json
index 908c8947..1429bedd 100644
--- a/resources/lib/oojs-ui/i18n/tg-cyrl.json
+++ b/resources/lib/oojs-ui/i18n/tg-cyrl.json
@@ -4,7 +4,6 @@
"Ibrahim"
]
},
- "ooui-dialog-action-close": "Пӯшиш",
"ooui-outline-control-move-down": "Ҳаракати мавод ба поён",
"ooui-outline-control-move-up": "Ҳаракати мавод ба боло",
"ooui-outline-control-remove": "Ҳазви мавод",
diff --git a/resources/lib/oojs-ui/i18n/th.json b/resources/lib/oojs-ui/i18n/th.json
index f36dd6a2..94527935 100644
--- a/resources/lib/oojs-ui/i18n/th.json
+++ b/resources/lib/oojs-ui/i18n/th.json
@@ -5,7 +5,6 @@
"Taweetham"
]
},
- "ooui-dialog-action-close": "ปิด",
"ooui-outline-control-move-down": "เลื่อนรายการลง",
"ooui-outline-control-move-up": "ย้ายรายการขึ้น"
}
diff --git a/resources/lib/oojs-ui/i18n/tl.json b/resources/lib/oojs-ui/i18n/tl.json
index 178384cd..b3a9f246 100644
--- a/resources/lib/oojs-ui/i18n/tl.json
+++ b/resources/lib/oojs-ui/i18n/tl.json
@@ -5,13 +5,10 @@
"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-outline-control-remove": "Tanggalin ang aytem",
"ooui-toolbar-more": "Marami pa",
- "ooui-dialog-confirm-title": "Tiyakin",
- "ooui-dialog-confirm-default-prompt": "Nakatitiyak ka ba?",
- "ooui-dialog-confirm-default-ok": "Sige",
- "ooui-dialog-confirm-default-cancel": "Huwag ituloy"
+ "ooui-dialog-message-accept": "Sige",
+ "ooui-dialog-message-reject": "Huwag ituloy"
}
diff --git a/resources/lib/oojs-ui/i18n/tr.json b/resources/lib/oojs-ui/i18n/tr.json
index 82f7c6c0..7b4d4921 100644
--- a/resources/lib/oojs-ui/i18n/tr.json
+++ b/resources/lib/oojs-ui/i18n/tr.json
@@ -8,11 +8,20 @@
"Rapsar",
"Talha Samil Cakir",
"TurkishStyles",
- "Sayginer"
+ "Sayginer",
+ "Meelo"
]
},
"ooui-outline-control-move-down": "Ögeyi aşağı taşı",
"ooui-outline-control-move-up": "Ögeyi yukarı taşı",
- "ooui-toolbar-more": "Daha fazla",
- "ooui-dialog-process-retry": "Tekrar dene"
+ "ooui-outline-control-remove": "Ögeyi kaldır",
+ "ooui-toolbar-more": "Dahası",
+ "ooui-toolgroup-expand": "Dahası",
+ "ooui-toolgroup-collapse": "Daha az",
+ "ooui-dialog-message-accept": "Tamam",
+ "ooui-dialog-message-reject": "İptal",
+ "ooui-dialog-process-error": "Bir şeyler yanlış gitti",
+ "ooui-dialog-process-dismiss": "Kapat",
+ "ooui-dialog-process-retry": "Tekrar dene",
+ "ooui-dialog-process-continue": "Devam et"
}
diff --git a/resources/lib/oojs-ui/i18n/tt-cyrl.json b/resources/lib/oojs-ui/i18n/tt-cyrl.json
index 257e13cd..408a1b4a 100644
--- a/resources/lib/oojs-ui/i18n/tt-cyrl.json
+++ b/resources/lib/oojs-ui/i18n/tt-cyrl.json
@@ -4,7 +4,6 @@
"Ajdar"
]
},
- "ooui-dialog-action-close": "Ябу",
"ooui-outline-control-move-down": "Элементны аска күчерү",
"ooui-outline-control-move-up": "Элементны өскә күчерү"
}
diff --git a/resources/lib/oojs-ui/i18n/uk.json b/resources/lib/oojs-ui/i18n/uk.json
index d6034f05..0197a4ce 100644
--- a/resources/lib/oojs-ui/i18n/uk.json
+++ b/resources/lib/oojs-ui/i18n/uk.json
@@ -14,16 +14,20 @@
"SteveR",
"Tel'et",
"Tifinaghes",
- "Ата"
+ "Ата",
+ "Piramidion"
]
},
"ooui-outline-control-move-down": "Перемістити елемент униз",
"ooui-outline-control-move-up": "Перемістити елемент вгору",
"ooui-outline-control-remove": "Видалити елемент",
"ooui-toolbar-more": "Більше",
+ "ooui-toolgroup-expand": "Більше",
+ "ooui-toolgroup-collapse": "Менше",
"ooui-dialog-message-accept": "Готово",
"ooui-dialog-message-reject": "Скасувати",
"ooui-dialog-process-error": "Щось пішло не так",
"ooui-dialog-process-dismiss": "Приховати",
- "ooui-dialog-process-retry": "Спробуйте ще раз"
+ "ooui-dialog-process-retry": "Спробуйте ще раз",
+ "ooui-dialog-process-continue": "Продовжити"
}
diff --git a/resources/lib/oojs-ui/i18n/uz.json b/resources/lib/oojs-ui/i18n/uz.json
index 03b78089..7c6263e4 100644
--- a/resources/lib/oojs-ui/i18n/uz.json
+++ b/resources/lib/oojs-ui/i18n/uz.json
@@ -7,7 +7,6 @@
"පසිඳු කාවින්ද"
]
},
- "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"
diff --git a/resources/lib/oojs-ui/i18n/vec.json b/resources/lib/oojs-ui/i18n/vec.json
index 1a91cdb0..4de584bf 100644
--- a/resources/lib/oojs-ui/i18n/vec.json
+++ b/resources/lib/oojs-ui/i18n/vec.json
@@ -6,10 +6,8 @@
"Gloria sah"
]
},
- "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",
- "ooui-dialog-confirm-title": "Conferma",
- "ooui-dialog-confirm-default-ok": "Va ben"
+ "ooui-dialog-message-accept": "Va ben"
}
diff --git a/resources/lib/oojs-ui/i18n/vi.json b/resources/lib/oojs-ui/i18n/vi.json
index 205cbe89..d5c1e364 100644
--- a/resources/lib/oojs-ui/i18n/vi.json
+++ b/resources/lib/oojs-ui/i18n/vi.json
@@ -3,16 +3,20 @@
"authors": [
"Cheers!",
"Jdforrester",
- "Minh Nguyen"
+ "Minh Nguyen",
+ "Max20091"
]
},
"ooui-outline-control-move-down": "Chuyển mục xuống",
"ooui-outline-control-move-up": "Chuyển mục lên",
"ooui-outline-control-remove": "Xóa khoản",
"ooui-toolbar-more": "Thêm",
+ "ooui-toolgroup-expand": "Mở rộng",
+ "ooui-toolgroup-collapse": "Rút gọn",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Hủy bỏ",
"ooui-dialog-process-error": "Đã bị trục trặc",
"ooui-dialog-process-dismiss": "Bỏ qua",
- "ooui-dialog-process-retry": "Thử lại"
+ "ooui-dialog-process-retry": "Thử lại",
+ "ooui-dialog-process-continue": "Tiếp tục"
}
diff --git a/resources/lib/oojs-ui/i18n/vo.json b/resources/lib/oojs-ui/i18n/vo.json
index 7e359a5c..3510ca93 100644
--- a/resources/lib/oojs-ui/i18n/vo.json
+++ b/resources/lib/oojs-ui/i18n/vo.json
@@ -4,6 +4,5 @@
"Malafaya"
]
},
- "ooui-dialog-action-close": "Färmükön",
"ooui-toolbar-more": "Pluikos"
}
diff --git a/resources/lib/oojs-ui/i18n/yo.json b/resources/lib/oojs-ui/i18n/yo.json
index bbb8f30d..d979fc13 100644
--- a/resources/lib/oojs-ui/i18n/yo.json
+++ b/resources/lib/oojs-ui/i18n/yo.json
@@ -4,7 +4,6 @@
"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"
diff --git a/resources/lib/oojs-ui/i18n/zh-hans.json b/resources/lib/oojs-ui/i18n/zh-hans.json
index 02bdafad..ed2f61e4 100644
--- a/resources/lib/oojs-ui/i18n/zh-hans.json
+++ b/resources/lib/oojs-ui/i18n/zh-hans.json
@@ -19,13 +19,16 @@
"Great Brightstar"
]
},
- "ooui-outline-control-move-down": "下移项",
- "ooui-outline-control-move-up": "上移项",
- "ooui-outline-control-remove": "删除项",
+ "ooui-outline-control-move-down": "项目下移",
+ "ooui-outline-control-move-up": "项目上移",
+ "ooui-outline-control-remove": "移除项目",
"ooui-toolbar-more": "更多",
+ "ooui-toolgroup-expand": "更多",
+ "ooui-toolgroup-collapse": "更少",
"ooui-dialog-message-accept": "确定",
"ooui-dialog-message-reject": "取消",
"ooui-dialog-process-error": "发生一些错误",
"ooui-dialog-process-dismiss": "解除",
- "ooui-dialog-process-retry": "重试"
+ "ooui-dialog-process-retry": "重试",
+ "ooui-dialog-process-continue": "继续"
}
diff --git a/resources/lib/oojs-ui/i18n/zh-hant.json b/resources/lib/oojs-ui/i18n/zh-hant.json
index 05fb20d1..3fd8d361 100644
--- a/resources/lib/oojs-ui/i18n/zh-hant.json
+++ b/resources/lib/oojs-ui/i18n/zh-hant.json
@@ -13,16 +13,20 @@
"Simon Shek",
"Spring Roll Conan",
"Waihorace",
- "Cwlin0416"
+ "Cwlin0416",
+ "LNDDYL"
]
},
"ooui-outline-control-move-down": "項目下移",
"ooui-outline-control-move-up": "項目上移",
"ooui-outline-control-remove": "移除項目",
"ooui-toolbar-more": "更多",
+ "ooui-toolgroup-expand": "更多",
+ "ooui-toolgroup-collapse": "更少",
"ooui-dialog-message-accept": "確定",
"ooui-dialog-message-reject": "取消",
"ooui-dialog-process-error": "發生不明錯誤",
- "ooui-dialog-process-dismiss": "放棄",
- "ooui-dialog-process-retry": "再試一次"
+ "ooui-dialog-process-dismiss": "關閉",
+ "ooui-dialog-process-retry": "再試一次",
+ "ooui-dialog-process-continue": "繼續"
}
diff --git a/resources/lib/oojs-ui/images/anchor.png b/resources/lib/oojs-ui/images/anchor.png
deleted file mode 100644
index 470a7ac7..00000000
--- a/resources/lib/oojs-ui/images/anchor.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/anchor.svg b/resources/lib/oojs-ui/images/anchor.svg
deleted file mode 100644
index 3694391e..00000000
--- a/resources/lib/oojs-ui/images/anchor.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="15" height="8" viewBox="0 0 15 8">
- <g id="anchor">
- <polygon id="outline" style="fill:#808080;" points="7.609,2.499 2.096,8 13.125,8"/>
- <polygon id="fill" style="fill:#FFFFFF;" points="7.609,3 2.598,8 12.622,8"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/grab.cur b/resources/lib/oojs-ui/images/grab.cur
new file mode 100644
index 00000000..fba3ddc8
--- /dev/null
+++ b/resources/lib/oojs-ui/images/grab.cur
Binary files differ
diff --git a/resources/lib/oojs-ui/images/grabbing.cur b/resources/lib/oojs-ui/images/grabbing.cur
new file mode 100644
index 00000000..41aaa62a
--- /dev/null
+++ b/resources/lib/oojs-ui/images/grabbing.cur
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/accept.png b/resources/lib/oojs-ui/images/icons/accept.png
deleted file mode 100644
index 76df4795..00000000
--- a/resources/lib/oojs-ui/images/icons/accept.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/accept.svg b/resources/lib/oojs-ui/images/icons/accept.svg
deleted file mode 100644
index b385a74c..00000000
--- a/resources/lib/oojs-ui/images/icons/accept.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="accept" opacity=".75">
- <path id="check" d="M19.062 5.139l-1.644-1.139-8.551 12.357-3.454-3.454-1.413 1.413 5.021 5.022z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/icons/add-item.png b/resources/lib/oojs-ui/images/icons/add-item.png
deleted file mode 100644
index a7788c72..00000000
--- a/resources/lib/oojs-ui/images/icons/add-item.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/advanced.png b/resources/lib/oojs-ui/images/icons/advanced.png
deleted file mode 100644
index 7609ec91..00000000
--- a/resources/lib/oojs-ui/images/icons/advanced.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/advanced.svg b/resources/lib/oojs-ui/images/icons/advanced.svg
deleted file mode 100644
index 0f85e44b..00000000
--- a/resources/lib/oojs-ui/images/icons/advanced.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="settings" opacity=".75">
- <path id="gear" d="M20.869 13.476c.079-.482.131-.972.131-1.476s-.052-.994-.131-1.476l-2.463-.259c-.149-.556-.367-1.082-.648-1.57l1.558-1.924c-.576-.806-1.281-1.511-2.087-2.087l-1.924 1.558c-.488-.281-1.015-.499-1.57-.648l-.259-2.463c-.482-.079-.972-.131-1.476-.131s-.994.052-1.476.131l-.259 2.463c-.555.149-1.081.367-1.57.648l-1.924-1.557c-.805.576-1.51 1.281-2.086 2.086l1.558 1.924c-.281.488-.499 1.015-.648 1.57l-2.463.259c-.08.482-.132.972-.132 1.476s.052.994.131 1.476l2.463.259c.149.556.367 1.082.648 1.57l-1.558 1.924c.576.806 1.281 1.511 2.087 2.087l1.924-1.558c.488.281 1.015.499 1.57.648l.259 2.463c.482.079.972.131 1.476.131s.994-.052 1.476-.131l.259-2.463c.556-.149 1.082-.367 1.57-.648l1.924 1.558c.806-.576 1.511-1.281 2.087-2.087l-1.558-1.924c.281-.488.499-1.015.648-1.57l2.463-.259zm-8.869 2.522c-2.209 0-3.998-1.789-3.998-3.998s1.789-3.998 3.998-3.998 3.998 1.789 3.998 3.998-1.789 3.998-3.998 3.998z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/icons/alert.png b/resources/lib/oojs-ui/images/icons/alert.png
deleted file mode 100644
index a45ad31e..00000000
--- a/resources/lib/oojs-ui/images/icons/alert.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/arched-arrow-ltr.png b/resources/lib/oojs-ui/images/icons/arched-arrow-ltr.png
deleted file mode 100644
index c48f55df..00000000
--- a/resources/lib/oojs-ui/images/icons/arched-arrow-ltr.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/arched-arrow-ltr.svg b/resources/lib/oojs-ui/images/icons/arched-arrow-ltr.svg
deleted file mode 100644
index 9fd2866f..00000000
--- a/resources/lib/oojs-ui/images/icons/arched-arrow-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="arched-arrow-ltr" opacity=".75">
- <path id="arrow" d="M19.925 14.937l-2.391-6.901-1.48 2.329c-.964-.845-2.699-1.85-5.513-1.823-4.887.046-6.524 4.244-6.524 4.244s2.753-2.639 6.925-1.949c1.729.286 3.007 1.206 3.675 1.791l-1.474 2.319 6.782-.01z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/icons/arched-arrow-rtl.png b/resources/lib/oojs-ui/images/icons/arched-arrow-rtl.png
deleted file mode 100644
index 51c8de4f..00000000
--- a/resources/lib/oojs-ui/images/icons/arched-arrow-rtl.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/arched-arrow-rtl.svg b/resources/lib/oojs-ui/images/icons/arched-arrow-rtl.svg
deleted file mode 100644
index b16c1b47..00000000
--- a/resources/lib/oojs-ui/images/icons/arched-arrow-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="arched-arrow-rtl" opacity=".75">
- <path id="arrow" d="M13.401 8.542c-2.814-.027-4.549.978-5.513 1.823l-1.48-2.329-2.391 6.901 6.782.009-1.474-2.319c.668-.584 1.945-1.504 3.675-1.791 4.172-.69 6.925 1.949 6.925 1.949s-1.637-4.197-6.524-4.243z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/icons/check.png b/resources/lib/oojs-ui/images/icons/check.png
deleted file mode 100644
index 9a2c9dbf..00000000
--- a/resources/lib/oojs-ui/images/icons/check.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/check.svg b/resources/lib/oojs-ui/images/icons/check.svg
deleted file mode 100644
index 8d4a1f8b..00000000
--- a/resources/lib/oojs-ui/images/icons/check.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
- <g id="check">
- <path d="M7.105 13.473l1.422-1.423 1.901 1.902 4.81-6.952 1.657 1.148-6.26 8.852z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/icons/clear.png b/resources/lib/oojs-ui/images/icons/clear.png
deleted file mode 100644
index 02d6bb39..00000000
--- a/resources/lib/oojs-ui/images/icons/clear.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/close.png b/resources/lib/oojs-ui/images/icons/close.png
deleted file mode 100644
index 06d49217..00000000
--- a/resources/lib/oojs-ui/images/icons/close.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/close.svg b/resources/lib/oojs-ui/images/icons/close.svg
deleted file mode 100644
index 3c0ab46d..00000000
--- a/resources/lib/oojs-ui/images/icons/close.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="close" opacity=".75">
- <path id="x" d="M18.717 6.697l-1.414-1.414-5.303 5.303-5.303-5.303-1.414 1.414 5.303 5.303-5.303 5.303 1.414 1.414 5.303-5.303 5.303 5.303 1.414-1.414-5.303-5.303z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/icons/code.png b/resources/lib/oojs-ui/images/icons/code.png
deleted file mode 100644
index 783e1e0d..00000000
--- a/resources/lib/oojs-ui/images/icons/code.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/collapse.png b/resources/lib/oojs-ui/images/icons/collapse.png
deleted file mode 100644
index 2c4ecee6..00000000
--- a/resources/lib/oojs-ui/images/icons/collapse.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/comment.png b/resources/lib/oojs-ui/images/icons/comment.png
deleted file mode 100644
index 5be2b72f..00000000
--- a/resources/lib/oojs-ui/images/icons/comment.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/expand.png b/resources/lib/oojs-ui/images/icons/expand.png
deleted file mode 100644
index 3ae27c06..00000000
--- a/resources/lib/oojs-ui/images/icons/expand.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/help.png b/resources/lib/oojs-ui/images/icons/help.png
deleted file mode 100644
index c1190fcc..00000000
--- a/resources/lib/oojs-ui/images/icons/help.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/history.png b/resources/lib/oojs-ui/images/icons/history.png
deleted file mode 100644
index 8a9862fc..00000000
--- a/resources/lib/oojs-ui/images/icons/history.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/info.png b/resources/lib/oojs-ui/images/icons/info.png
deleted file mode 100644
index a74fb186..00000000
--- a/resources/lib/oojs-ui/images/icons/info.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/link.png b/resources/lib/oojs-ui/images/icons/link.png
deleted file mode 100644
index e51657d0..00000000
--- a/resources/lib/oojs-ui/images/icons/link.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/link.svg b/resources/lib/oojs-ui/images/icons/link.svg
deleted file mode 100644
index fcb06be0..00000000
--- a/resources/lib/oojs-ui/images/icons/link.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="link" opacity=".75">
- <path id="right" d="M19.188 12.001c0 1.1-.891 2.015-1.988 2.015l-4.195-.015c.538 1.088.963 1.999 1.997 1.999h3c1.656 0 2.998-2.343 2.998-4s-1.342-4-2.998-4h-3c-1.034 0-1.459.911-1.998 1.999l4.195-.015c1.098 0 1.989.917 1.989 2.017z"/>
- <path id="center" d="M8 12c0 .535.42 1 .938 1h6.109c.518 0 .938-.465.938-1 0-.534-.42-1-.938-1h-6.109c-.518 0-.938.466-.938 1z"/>
- <path id="left" d="M4.816 11.999c0-1.1.891-2.015 1.988-2.015l4.196.015c-.539-1.088-.964-1.999-1.998-1.999h-3c-1.656 0-2.998 2.343-2.998 4s1.342 4 2.998 4h3c1.034 0 1.459-.911 1.998-1.999l-4.195.015c-1.098 0-1.989-.917-1.989-2.017z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/icons/menu.png b/resources/lib/oojs-ui/images/icons/menu.png
deleted file mode 100644
index e53aed64..00000000
--- a/resources/lib/oojs-ui/images/icons/menu.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/menu.svg b/resources/lib/oojs-ui/images/icons/menu.svg
deleted file mode 100644
index 2d047896..00000000
--- a/resources/lib/oojs-ui/images/icons/menu.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="menu" opacity=".75">
- <path id="lines" d="M6 15h12c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1h-12c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1zm-1-4v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1zm0-5v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1h-12c-.553 0-1 .447-1 1z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/icons/move-ltr.png b/resources/lib/oojs-ui/images/icons/move-ltr.png
deleted file mode 100644
index 4b9f3bfd..00000000
--- a/resources/lib/oojs-ui/images/icons/move-ltr.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/move-rtl.png b/resources/lib/oojs-ui/images/icons/move-rtl.png
deleted file mode 100644
index 7cd9cff5..00000000
--- a/resources/lib/oojs-ui/images/icons/move-rtl.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/picture.png b/resources/lib/oojs-ui/images/icons/picture.png
deleted file mode 100644
index ef9daec2..00000000
--- a/resources/lib/oojs-ui/images/icons/picture.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/remove-item.svg b/resources/lib/oojs-ui/images/icons/remove-item.svg
deleted file mode 100644
index 723e70fb..00000000
--- a/resources/lib/oojs-ui/images/icons/remove-item.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
- <g id="remove-item">
- <path id="minus" d="M8 11h8v2h-8z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/icons/remove.png b/resources/lib/oojs-ui/images/icons/remove.png
deleted file mode 100644
index 8baeee0a..00000000
--- a/resources/lib/oojs-ui/images/icons/remove.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/search.png b/resources/lib/oojs-ui/images/icons/search.png
deleted file mode 100644
index 19bc1784..00000000
--- a/resources/lib/oojs-ui/images/icons/search.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/search.svg b/resources/lib/oojs-ui/images/icons/search.svg
deleted file mode 100644
index 75b38c8f..00000000
--- a/resources/lib/oojs-ui/images/icons/search.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="search" opacity=".75">
- <path id="magnifying-glass" d="M16.021 15.96l-2.374-2.375-.169-.099c.403-.566.643-1.26.643-2.009-.001-1.92-1.558-3.477-3.477-3.477-1.921 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.749 0 1.442-.239 2.01-.643l.098.169 2.375 2.374c.19.189.543.143.79-.104s.293-.601.104-.791zm-5.377-2.27c-1.221 0-2.213-.991-2.213-2.213 0-1.221.992-2.213 2.213-2.213 1.222 0 2.213.992 2.213 2.213-.001 1.222-.992 2.213-2.213 2.213z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/icons/settings.png b/resources/lib/oojs-ui/images/icons/settings.png
deleted file mode 100644
index 0314960c..00000000
--- a/resources/lib/oojs-ui/images/icons/settings.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/tag.png b/resources/lib/oojs-ui/images/icons/tag.png
deleted file mode 100644
index 98028564..00000000
--- a/resources/lib/oojs-ui/images/icons/tag.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/window.png b/resources/lib/oojs-ui/images/icons/window.png
deleted file mode 100644
index bee8a3d9..00000000
--- a/resources/lib/oojs-ui/images/icons/window.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/indicators/alert.png b/resources/lib/oojs-ui/images/indicators/alert.png
deleted file mode 100644
index dc41e497..00000000
--- a/resources/lib/oojs-ui/images/indicators/alert.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/indicators/arrow-down.png b/resources/lib/oojs-ui/images/indicators/arrow-down.png
deleted file mode 100644
index edbc84f7..00000000
--- a/resources/lib/oojs-ui/images/indicators/arrow-down.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/indicators/arrow-down.svg b/resources/lib/oojs-ui/images/indicators/arrow-down.svg
deleted file mode 100644
index 55670deb..00000000
--- a/resources/lib/oojs-ui/images/indicators/arrow-down.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="down" opacity=".75">
- <path id="arrow" d="M2 3l3.5 6 3.5-6z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/indicators/arrow-ltr.png b/resources/lib/oojs-ui/images/indicators/arrow-ltr.png
deleted file mode 100644
index 8a85a05b..00000000
--- a/resources/lib/oojs-ui/images/indicators/arrow-ltr.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/indicators/arrow-ltr.svg b/resources/lib/oojs-ui/images/indicators/arrow-ltr.svg
deleted file mode 100644
index 5092d889..00000000
--- a/resources/lib/oojs-ui/images/indicators/arrow-ltr.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="ltr" opacity=".75">
- <path id="arrow" d="M3 9v-7l6 3.5z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/indicators/arrow-rtl.png b/resources/lib/oojs-ui/images/indicators/arrow-rtl.png
deleted file mode 100644
index 07cc8885..00000000
--- a/resources/lib/oojs-ui/images/indicators/arrow-rtl.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/indicators/arrow-rtl.svg b/resources/lib/oojs-ui/images/indicators/arrow-rtl.svg
deleted file mode 100644
index 8d39de82..00000000
--- a/resources/lib/oojs-ui/images/indicators/arrow-rtl.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="rtl" opacity=".75">
- <path id="arrow" d="M3 5.5l6 3.5v-7z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/indicators/arrow-up.png b/resources/lib/oojs-ui/images/indicators/arrow-up.png
deleted file mode 100644
index f25858d7..00000000
--- a/resources/lib/oojs-ui/images/indicators/arrow-up.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/indicators/arrow-up.svg b/resources/lib/oojs-ui/images/indicators/arrow-up.svg
deleted file mode 100644
index b9d725e4..00000000
--- a/resources/lib/oojs-ui/images/indicators/arrow-up.svg
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="up" opacity=".75">
- <path id="arrow" d="M5.5 2l-3.5 6h7z"/>
- </g>
-</svg>
diff --git a/resources/lib/oojs-ui/images/indicators/required.png b/resources/lib/oojs-ui/images/indicators/required.png
deleted file mode 100644
index bca07c60..00000000
--- a/resources/lib/oojs-ui/images/indicators/required.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/images/toolbar-shadow.png b/resources/lib/oojs-ui/images/toolbar-shadow.png
deleted file mode 100644
index 97e8d13d..00000000
--- a/resources/lib/oojs-ui/images/toolbar-shadow.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/oojs-ui-apex.css b/resources/lib/oojs-ui/oojs-ui-apex.css
deleted file mode 100644
index fdf41ae6..00000000
--- a/resources/lib/oojs-ui/oojs-ui-apex.css
+++ /dev/null
@@ -1,1945 +0,0 @@
-/*!
- * OOjs UI v0.1.0-pre (f2c3f12959)
- * 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: 2014-09-18T23:22:20Z
- */
-/*
- * Blank theme mixins.
- *
- * Base styles invoke these mixins at the end of their definitions. Override these mixins to add
- * additional rules to the base styles.
- */
-/*
- * Base styles.
- *
- * Themes should include this file after defining their variables and mixins.
- */
-/* @noflip */
-.oo-ui-rtl {
- direction: rtl;
-}
-/* @noflip */
-.oo-ui-ltr {
- direction: ltr;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button {
- 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-buttonElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- display: none;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- display: none;
-}
-.oo-ui-buttonElement.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
- cursor: default;
-}
-.oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
-.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-buttonElement-frameless {
- display: inline-block;
- position: relative;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
- display: inline-block;
- vertical-align: top;
- text-align: center;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- cursor: default;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button {
- color: #333333;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-left: 0;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- margin-right: -0.75em;
-}
-.oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
-.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- opacity: 0.8;
- width: 1.9em;
- height: 1.9em;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- /* Don't animate opacities for now, causes wiggling in Chrome (bug 63020) */
- /*.oo-ui-transition(opacity 200ms);*/
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:hover > .oo-ui-iconElement-icon,
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:focus > .oo-ui-iconElement-icon {
- opacity: 1;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
- color: #000000;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #333333;
- margin-left: 0.25em;
-}
-.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #087ecc;
-}
-.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #76ab36;
-}
-.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #d45353;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #cccccc;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
- margin: 0.1em 0;
- padding: 0.2em 0.8em;
- border-radius: 0.3em;
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
- border: 1px #c9c9c9 solid;
- -webkit-transition: border-color 100ms ease-in-out;
- -moz-transition: border-color 100ms ease-in-out;
- -ms-transition: border-color 100ms ease-in-out;
- -o-transition: border-color 100ms ease-in-out;
- transition: border-color 100ms ease-in-out;
- background: #eeeeee;
- 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-buttonElement-framed > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button:focus {
- border-color: #aaaaaa;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- line-height: 1.9em;
-}
-.oo-ui-buttonElement-framed.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
- color: black;
- border-color: #c9c9c9;
- background: #eeeeee;
- 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-buttonElement-framed.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-left: -0.5em;
- margin-right: -0.5em;
-}
-.oo-ui-buttonElement-framed.oo-ui-iconElement.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-left: -0.5em;
- margin-right: 0.3em;
-}
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button {
- border: solid 1px #a6cee1;
- background: #cde7f4;
- 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-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:focus {
- border-color: #9dc2d4;
-}
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- border: solid 1px #a6cee1;
- background: #cde7f4;
- 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-buttonElement-framed.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
- border: solid 1px #b8d892;
- background: #daf0be;
- 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-buttonElement-framed.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
- border-color: #adcb89;
-}
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-constructive.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-constructive.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- border: solid 1px #b8d892;
- background: #daf0be;
- 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-buttonElement-framed.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
- color: #d45353;
-}
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- opacity: 0.5;
- box-shadow: none;
- color: #333333;
- background: #eeeeee;
- border-color: #cccccc;
-}
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button:focus,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button:focus,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button:focus {
- border-color: #cccccc;
- box-shadow: none;
-}
-.oo-ui-clippableElement-clippable {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
- overflow-y: hidden;
-}
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
- 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-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;
-}
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
- padding: 1.5em;
-}
-.oo-ui-bookletLayout-outlinePanel {
- border-right: solid 1px #dddddd;
-}
-.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
- box-shadow: 0 0 0.25em rgba(0, 0, 0, 0.25);
-}
-.oo-ui-fieldLayout {
- margin-bottom: 1em;
-}
-.oo-ui-fieldLayout:before,
-.oo-ui-fieldLayout:after {
- content: " ";
- display: table;
-}
-.oo-ui-fieldLayout:after {
- clear: both;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- display: block;
- float: left;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
- display: block;
- float: left;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- text-align: right;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
- display: inline-block;
-}
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
- z-index: 1;
-}
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help {
- float: right;
-}
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help-content {
- padding: 0.5em 0.75em;
-}
-.oo-ui-fieldLayout:last-child {
- margin-bottom: 0;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- padding-top: 0.5em;
- margin-right: 5%;
- width: 35%;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
- width: 60%;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
- padding: 0.75em 0.5em 0.5em 0.5em;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
- padding: 0.5em 0;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
- padding: 0.5em 0;
-}
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-top: 0.25em;
-}
-.oo-ui-fieldLayout-disabled .oo-ui-labelElement-label {
- color: #cccccc;
-}
-.oo-ui-fieldsetLayout {
- position: relative;
- margin: 0;
- padding: 0;
- border: none;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
- display: block;
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-fieldsetLayout.oo-ui-labelElement > .oo-ui-labelElement-label {
- display: inline-block;
-}
-.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout {
- margin-top: 2em;
-}
-.oo-ui-fieldsetLayout > .oo-ui-labelElement-label {
- font-size: 1.5em;
- margin-bottom: 0.5em;
- padding: 0.25em 0;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-labelElement-label {
- padding-left: 1.75em;
- line-height: 1.33em;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
- left: 0;
- top: 0.25em;
- width: 2em;
- height: 2em;
-}
-.oo-ui-gridLayout {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
-}
-.oo-ui-panelLayout {
- position: relative;
-}
-.oo-ui-panelLayout-scrollable {
- overflow-y: auto;
-}
-.oo-ui-panelLayout-expanded {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
-}
-.oo-ui-panelLayout-padded {
- padding: 1.25em;
-}
-.oo-ui-stackLayout > .oo-ui-panelLayout {
- display: none;
-}
-.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
- display: block;
- position: relative;
-}
-.oo-ui-popupTool .oo-ui-popupWidget-popup,
-.oo-ui-popupTool .oo-ui-popupWidget-anchor {
- z-index: 4;
-}
-.oo-ui-popupTool .oo-ui-popupWidget {
- margin-left: 1.25em;
- font-size: 0.8em;
-}
-.oo-ui-toolGroup {
- display: inline-block;
- vertical-align: middle;
- margin: 0.3em;
- border-radius: 0.25em;
- border: solid 1px transparent;
- -webkit-transition: border-color 300ms ease-in-out;
- -moz-transition: border-color 300ms ease-in-out;
- -ms-transition: border-color 300ms ease-in-out;
- -o-transition: border-color 300ms ease-in-out;
- transition: border-color 300ms ease-in-out;
-}
-.oo-ui-toolGroup-empty {
- display: none;
-}
-.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-toolGroup.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-toolGroup.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-tool-title {
- color: #000000;
-}
-.oo-ui-barToolGroup > .oo-ui-iconElement-icon,
-.oo-ui-barToolGroup > .oo-ui-labelElement-label {
- display: none;
-}
-.oo-ui-barToolGroup .oo-ui-tool {
- display: inline-block;
- position: relative;
- vertical-align: top;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link {
- display: block;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- display: block;
-}
-.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-title,
-.oo-ui-barToolGroup .oo-ui-tool-accel {
- display: none;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-link {
- cursor: pointer;
-}
-.oo-ui-barToolGroup .oo-ui-tool {
- margin: -1px 0 -1px -1px;
- border: solid 1px transparent;
-}
-.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-link {
- height: 1.5em;
- padding: 0.25em;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- height: 1.5em;
- width: 1.5em;
- opacity: 0.8;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-active.oo-ui-widget-enabled {
- border-color: rgba(0, 0, 0, 0.2);
- box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
- background: #f8fbfd;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f1f7fb', endColorstr='#ffffff');
- background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0%, #f1f7fb), color-stop(100%, #ffffff));
- background-image: -webkit-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -moz-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -ms-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
- border-left-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.8;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-enabled:hover .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 1;
-}
-.oo-ui-barToolGroup.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-popupToolGroup {
- position: relative;
- height: 2em;
- min-width: 2.5em;
-}
-.oo-ui-popupToolGroup-handle {
- display: block;
- cursor: pointer;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-popupToolGroup.oo-ui-widget-disabled .oo-ui-popupToolGroup-handle {
- cursor: default;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
- display: none;
- position: absolute;
- z-index: 4;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconElement-icon {
- background-repeat: no-repeat;
- background-position: center center;
-}
-.oo-ui-popupToolGroup-active.oo-ui-widget-enabled > .oo-ui-toolGroup-tools {
- display: block;
-}
-.oo-ui-popupToolGroup-left > .oo-ui-toolGroup-tools {
- left: 0;
-}
-.oo-ui-popupToolGroup-right > .oo-ui-toolGroup-tools {
- right: 0;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-accel {
- display: none;
-}
-.oo-ui-popupToolGroup.oo-ui-indicatorElement.oo-ui-iconElement {
- min-width: 3.5em;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- top: 0;
- width: 2em;
- height: 2em;
- opacity: 0.8;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
- right: 0;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- left: 0.25em;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- line-height: 2.6em;
- font-size: 0.8em;
- margin: 0 1em;
-}
-.oo-ui-popupToolGroup-header {
- line-height: 2.6em;
- font-size: 0.8em;
- margin: 0 0.6em;
- font-weight: bold;
-}
-.oo-ui-popupToolGroup-active.oo-ui-widget-enabled {
- border-bottom-left-radius: 0;
- border-bottom-right-radius: 0;
- box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
- background: #f8fbfd;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f1f7fb', endColorstr='#ffffff');
- background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0%, #f1f7fb), color-stop(100%, #ffffff));
- background-image: -webkit-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -moz-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -ms-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
-}
-.oo-ui-popupToolGroup.oo-ui-iconElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-left: 3em;
-}
-.oo-ui-popupToolGroup.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-right: 2.25em;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
- top: 2em;
- margin: 0 -1px;
- border: solid 1px #cccccc;
- background-color: white;
- box-shadow: 0 0.25em 1em rgba(0, 0, 0, 0.25);
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- height: 2em;
- width: 2em;
- margin-right: 0.25em;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
- line-height: 2em;
- font-size: 0.8em;
-}
-.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;
-}
-.oo-ui-listToolGroup .oo-ui-tool-link {
- display: block;
- cursor: pointer;
- white-space: nowrap;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
-.oo-ui-listToolGroup .oo-ui-toolGroup-tools {
- padding: 0.25em;
-}
-.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-listToolGroup .oo-ui-tool {
- border: solid 1px transparent;
- margin: -1px 0;
-}
-.oo-ui-listToolGroup .oo-ui-tool-link {
- padding-right: 0.5em;
-}
-.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled {
- border-color: rgba(0, 0, 0, 0.1);
- box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
- background: #f8fbfd;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f1f7fb', endColorstr='#ffffff');
- background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0%, #f1f7fb), color-stop(100%, #ffffff));
- background-image: -webkit-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -moz-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -ms-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
-}
-.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
- border-top-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.8;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 1;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
- color: #cccccc;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-listToolGroup.oo-ui-widget-disabled {
- color: #cccccc;
-}
-.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
-.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-menuToolGroup {
- border-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-menuToolGroup .oo-ui-tool {
- display: block;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-link {
- display: block;
- cursor: pointer;
- white-space: nowrap;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-image: none;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-image: /* @embed */ url(images/icons/check.svg);
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
-.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
- min-width: 8em;
-}
-.oo-ui-menuToolGroup .oo-ui-toolGroup-tools {
- padding: 0.25em 0 0.25em 0;
-}
-.oo-ui-menuToolGroup.oo-ui-widget-enabled: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-tool-link {
- padding: 0 1em 0 0.25em;
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
- background-color: #e1f3ff;
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
- color: #cccccc;
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-menuToolGroup.oo-ui-widget-disabled {
- color: #cccccc;
- border-color: rgba(0, 0, 0, 0.05);
-}
-.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
-.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-toolbar {
- clear: both;
-}
-.oo-ui-toolbar-bar {
- line-height: 1em;
-}
-.oo-ui-toolbar-actions {
- float: right;
-}
-.oo-ui-toolbar-tools {
- display: inline;
-}
-.oo-ui-toolbar-tools,
-.oo-ui-toolbar-actions,
-.oo-ui-toolbar-shadow {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-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 {
- background-position: left top;
- background-repeat: repeat-x;
- position: absolute;
- width: 100%;
- pointer-events: none;
-}
-.oo-ui-toolbar-bar {
- border-bottom: solid 1px #cccccc;
- background: #f8fbfd;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#ffffff', endColorstr='#f1f7fb');
- background-image: -webkit-gradient(linear, right top, right bottom, color-stop(0%, #ffffff), color-stop(100%, #f1f7fb));
- background-image: -webkit-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
- background-image: -moz-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
- background-image: -ms-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
- background-image: -o-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
- background-image: linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
-}
-.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
- border: none;
- background: none;
-}
-.oo-ui-toolbar-shadow {
- background-image: /* @embed */ url(images/toolbar-shadow.png);
- bottom: -9px;
- height: 9px;
- opacity: 0.125;
- -webkit-transition: opacity 500ms ease-in-out;
- -moz-transition: opacity 500ms ease-in-out;
- -ms-transition: opacity 500ms ease-in-out;
- -o-transition: opacity 500ms ease-in-out;
- transition: opacity 500ms ease-in-out;
-}
-.oo-ui-optionWidget {
- position: relative;
- display: block;
- cursor: pointer;
- padding: 0.5em 2em 0.5em 3em;
- border: none;
-}
-.oo-ui-optionWidget.oo-ui-widget-disabled {
- cursor: default;
-}
-.oo-ui-optionWidget .oo-ui-labelElement-label {
- display: block;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
-}
-.oo-ui-optionWidget-highlighted {
- background-color: #e1f3ff;
-}
-.oo-ui-optionWidget .oo-ui-labelElement-label {
- line-height: 1.5em;
-}
-.oo-ui-selectWidget-depressed .oo-ui-optionWidget-selected {
- background-color: #a7dcff;
-}
-.oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed {
- background-color: #a7dcff;
-}
-.oo-ui-optionWidget.oo-ui-widget-disabled {
- color: #cccccc;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon,
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- position: absolute;
- background-repeat: no-repeat;
- background-position: center center;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon,
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- top: 50%;
- width: 2em;
- height: 2em;
- margin-top: -1em;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon {
- left: 0.5em;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- right: 0.5em;
-}
-.oo-ui-buttonSelectWidget {
- display: inline-block;
- white-space: nowrap;
- border-radius: 0.3em;
-}
-.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-left: -1px;
-}
-.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonElement-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-buttonElement-button {
- border-bottom-right-radius: 0.3em;
- border-top-right-radius: 0.3em;
-}
-.oo-ui-buttonOptionWidget {
- display: inline-block;
- padding: 0;
- background-color: transparent;
-}
-.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- position: relative;
-}
-.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
-.oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- position: static;
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- height: 1.9em;
-}
-.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
-.oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- height: 1.9em;
- margin-top: 0;
-}
-.oo-ui-buttonOptionWidget.oo-ui-optionWidget-selected,
-.oo-ui-buttonOptionWidget.oo-ui-optionWidget-pressed,
-.oo-ui-buttonOptionWidget.oo-ui-optionWidget-highlighted {
- background-color: transparent;
-}
-.oo-ui-labelWidget {
- display: inline-block;
- padding: 0.5em 0;
-}
-.oo-ui-iconWidget {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- line-height: 2.5em;
- height: 1.9em;
- width: 1.9em;
- opacity: 0.8;
-}
-.oo-ui-iconWidget.oo-ui-widget-disabled {
- opacity: 0.2;
-}
-.oo-ui-indicatorWidget {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- line-height: 2.5em;
- height: 1.9em;
- width: 1.9em;
- opacity: 0.8;
-}
-.oo-ui-indicatorWidget.oo-ui-widget-disabled {
- opacity: 0.2;
-}
-.oo-ui-buttonWidget {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonGroupWidget {
- display: inline-block;
- white-space: nowrap;
- border-radius: 0.3em;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-bottom: -1px;
- margin-left: -1px;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:first-child .oo-ui-buttonElement-button {
- border-bottom-left-radius: 0.3em;
- border-top-left-radius: 0.3em;
- margin-left: 0;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:last-child .oo-ui-buttonElement-button {
- border-bottom-right-radius: 0.3em;
- border-top-right-radius: 0.3em;
-}
-.oo-ui-toggleSwitchWidget {
- position: relative;
- display: inline-block;
- vertical-align: middle;
- overflow: hidden;
- 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);
- height: 2em;
- width: 4em;
- border-radius: 1em;
- box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #dddddd;
- border: solid 1px #cccccc;
- background: #eeeeee;
- 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 {
- cursor: default;
-}
-.oo-ui-toggleSwitchWidget-grip {
- position: absolute;
- display: block;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
- position: absolute;
- top: 0;
- bottom: 0;
- right: 0;
- left: 0;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
- display: none;
-}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
- opacity: 0.5;
-}
-.oo-ui-toggleSwitchWidget-grip {
- top: 0.25em;
- left: 0.25em;
- width: 1.5em;
- height: 1.5em;
- margin-top: -1px;
- border-radius: 1em;
- box-shadow: 0 0.1em 0.25em rgba(0, 0, 0, 0.1);
- border: 1px #c9c9c9 solid;
- -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;
- -ms-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;
- background: #eeeeee;
- 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.oo-ui-widget-enabled:hover,
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover .oo-ui-toggleSwitchWidget-grip {
- border-color: #aaaaaa;
-}
-.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
- border-radius: 1em;
- box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
- -webkit-transition: opacity 200ms ease-in-out;
- -moz-transition: opacity 200ms ease-in-out;
- -ms-transition: opacity 200ms ease-in-out;
- -o-transition: opacity 200ms ease-in-out;
- transition: opacity 200ms ease-in-out;
- background: #cde7f4;
- 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-glow {
- opacity: 1;
-}
-.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
- left: 2.25em;
- margin-left: -2px;
-}
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
- display: block;
- opacity: 0;
-}
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
- left: 0.25em;
- margin-left: 0;
-}
-.oo-ui-actionWidget.oo-ui-pendingElement-pending {
- background-image: /* @embed */ url(images/textures/pending.gif);
-}
-.oo-ui-popupWidget-popup {
- position: absolute;
- overflow: hidden;
- z-index: 1;
-}
-.oo-ui-popupWidget-anchor {
- display: none;
- z-index: 1;
-}
-.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
- display: block;
- position: absolute;
- background-repeat: no-repeat;
-}
-.oo-ui-popupWidget-head {
- -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;
-}
-.oo-ui-popupWidget-head .oo-ui-labelElement-label {
- float: left;
- cursor: default;
-}
-.oo-ui-popupWidget-body {
- clear: both;
- overflow: hidden;
-}
-.oo-ui-popupWidget-popup {
- border: solid 1px #cccccc;
- border-radius: 0.25em;
- background-color: #ffffff;
- box-shadow: 0 0.15em 0.5em 0 rgba(0, 0, 0, 0.2);
-}
-.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
- margin-top: 7px;
-}
-.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
- width: 15px;
- height: 8px;
- margin-left: -7px;
- background-image: /* @embed */ url(images/anchor.svg);
-}
-.oo-ui-popupWidget-transitioning .oo-ui-popupWidget-popup {
- -webkit-transition: width 100ms ease-in-out, height 100ms ease-in-out, left 100ms ease-in-out;
- -moz-transition: width 100ms ease-in-out, height 100ms ease-in-out, left 100ms ease-in-out;
- -ms-transition: width 100ms ease-in-out, height 100ms ease-in-out, left 100ms ease-in-out;
- -o-transition: width 100ms ease-in-out, height 100ms ease-in-out, left 100ms ease-in-out;
- transition: width 100ms ease-in-out, height 100ms ease-in-out, left 100ms ease-in-out;
-}
-.oo-ui-popupWidget-head {
- height: 2.5em;
-}
-.oo-ui-popupWidget-head .oo-ui-buttonWidget {
- margin: 0.25em;
-}
-.oo-ui-popupWidget-head .oo-ui-labelElement-label {
- margin: 0.75em 1em;
-}
-.oo-ui-popupWidget-body {
- box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
-}
-.oo-ui-popupWidget-body-padded {
- padding: 0 1em;
-}
-.oo-ui-popupButtonWidget {
- position: relative;
-}
-.oo-ui-popupButtonWidget .oo-ui-popupWidget {
- position: absolute;
- left: 1em;
- cursor: auto;
-}
-.oo-ui-textInputWidget {
- position: relative;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- width: 20em;
-}
-.oo-ui-textInputWidget input,
-.oo-ui-textInputWidget textarea {
- display: inline-block;
- width: 100%;
- resize: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-textInputWidget.oo-ui-pendingElement-pending input,
-.oo-ui-textInputWidget.oo-ui-pendingElement-pending textarea {
- background-image: /* @embed */ url(images/textures/pending.gif);
-}
-.oo-ui-textInputWidget > .oo-ui-iconElement-icon,
-.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator {
- position: absolute;
- top: 0;
- height: 100%;
- background-repeat: no-repeat;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-textInputWidget > .oo-ui-iconElement-icon {
- left: 0;
-}
-.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator {
- right: 0;
-}
-.oo-ui-textInputWidget input,
-.oo-ui-textInputWidget textarea {
- padding: 0.5em;
- font-size: 1em;
- font-family: sans-serif;
- background-color: #ffffff;
- border: solid 1px #cccccc;
- box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #dddddd;
- border-radius: 0.25em;
- -webkit-transition: border-color 200ms, box-shadow 200ms;
- -moz-transition: border-color 200ms, box-shadow 200ms;
- -ms-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-decorated input,
-.oo-ui-textInputWidget-decorated textarea {
- padding-left: 2em;
-}
-.oo-ui-textInputWidget-icon {
- width: 2em;
-}
-.oo-ui-textInputWidget.oo-ui-widget-enabled input:focus,
-.oo-ui-textInputWidget.oo-ui-widget-enabled 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: #777777;
- text-shadow: 0 1px 1px #ffffff;
-}
-.oo-ui-textInputWidget.oo-ui-pendingElement-pending input,
-.oo-ui-textInputWidget.oo-ui-pendingElement-pending textarea {
- background-color: transparent;
-}
-.oo-ui-textInputWidget.oo-ui-widget-disabled input,
-.oo-ui-textInputWidget.oo-ui-widget-disabled input:focus,
-.oo-ui-textInputWidget.oo-ui-widget-disabled textarea,
-.oo-ui-textInputWidget.oo-ui-widget-disabled textarea:focus {
- color: #cccccc;
- text-shadow: 0 1px 1px #ffffff;
- border-color: #dddddd;
- background-color: #f3f3f3;
-}
-.oo-ui-textInputWidget .oo-ui-iconElement-icon,
-.oo-ui-textInputWidget .oo-ui-indicatorElement-indicator {
- opacity: 0.8;
-}
-.oo-ui-textInputWidget.oo-ui-iconElement input,
-.oo-ui-textInputWidget.oo-ui-iconElement textarea {
- padding-left: 2em;
-}
-.oo-ui-textInputWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- width: 2em;
- background-position: right center;
-}
-.oo-ui-textInputWidget.oo-ui-indicatorElement input,
-.oo-ui-textInputWidget.oo-ui-indicatorElement textarea {
- padding-right: 1.5em;
-}
-.oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- width: 1.5em;
- background-position: left center;
-}
-.oo-ui-menuWidget {
- position: absolute;
- background: #ffffff;
- margin-top: -1px;
- border: solid 1px #cccccc;
- 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 {
- position: relative;
-}
-.oo-ui-menuItemWidget .oo-ui-iconElement-icon {
- display: none;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
- background-color: transparent;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected .oo-ui-iconElement-icon {
- display: block;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
- background-color: transparent;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-highlighted,
-.oo-ui-menuItemWidget.oo-ui-optionWidget-highlighted.oo-ui-optionWidget-selected {
- background-color: #e1f3ff;
-}
-.oo-ui-menuSectionItemWidget {
- cursor: default;
- padding: 0.33em 0.75em;
- color: #888888;
-}
-.oo-ui-inlineMenuWidget {
- position: relative;
- display: inline-block;
- margin: 0.25em 0;
- min-width: 20em;
-}
-.oo-ui-inlineMenuWidget-handle {
- width: 100%;
- display: inline-block;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-inlineMenuWidget .oo-ui-menuWidget {
- z-index: 1;
- width: 100%;
-}
-.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-inlineMenuWidget-handle {
- cursor: default;
-}
-.oo-ui-inlineMenuWidget-handle {
- height: 2.5em;
- border: solid 1px rgba(0, 0, 0, 0.1);
- border-radius: 0.25em;
-}
-.oo-ui-inlineMenuWidget-handle:hover {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator {
- right: 0;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- left: 0.25em;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- line-height: 2.5em;
- margin: 0 0.5em;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- top: 0;
- width: 2.5em;
- height: 2.5em;
- opacity: 0.8;
-}
-.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-inlineMenuWidget-handle {
- color: #cccccc;
- text-shadow: 0 1px 1px #ffffff;
- border-color: #dddddd;
- background-color: #f3f3f3;
-}
-.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
-}
-.oo-ui-inlineMenuWidget.oo-ui-iconElement .oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- margin-left: 3em;
-}
-.oo-ui-inlineMenuWidget.oo-ui-indicatorElement .oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- margin-right: 2em;
-}
-.oo-ui-outlineItemWidget {
- position: relative;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- font-size: 1.1em;
- padding: 0.75em;
-}
-.oo-ui-outlineItemWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
- padding-right: 1.5em;
-}
-.oo-ui-outlineItemWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- opacity: 0.5;
-}
-.oo-ui-outlineItemWidget-level-0 {
- padding-left: 3.5em;
-}
-.oo-ui-outlineItemWidget-level-0 .oo-ui-iconElement-icon {
- left: 1em;
-}
-.oo-ui-outlineItemWidget-level-1 {
- padding-left: 5em;
-}
-.oo-ui-outlineItemWidget-level-1 .oo-ui-iconElement-icon {
- left: 2.5em;
-}
-.oo-ui-outlineItemWidget-level-2 {
- padding-left: 6.5em;
-}
-.oo-ui-outlineItemWidget-level-2 .oo-ui-iconElement-icon {
- left: 4em;
-}
-.oo-ui-selectWidget-depressed .oo-ui-outlineItemWidget.oo-ui-optionWidget-selected {
- background-color: #a7dcff;
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
-}
-.oo-ui-outlineItemWidget.oo-ui-flaggedElement-important {
- font-weight: bold;
-}
-.oo-ui-outlineItemWidget.oo-ui-flaggedElement-placeholder {
- font-style: italic;
-}
-.oo-ui-outlineItemWidget.oo-ui-flaggedElement-empty .oo-ui-iconElement-icon {
- opacity: 0.5;
-}
-.oo-ui-outlineItemWidget.oo-ui-flaggedElement-empty .oo-ui-labelElement-label {
- color: #777777;
-}
-.oo-ui-outlineControlsWidget {
- height: 3em;
- background-color: #ffffff;
-}
-.oo-ui-outlineControlsWidget-items,
-.oo-ui-outlineControlsWidget-movers {
- float: left;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
- float: left;
- background-position: right center;
- background-repeat: no-repeat;
-}
-.oo-ui-outlineControlsWidget-items {
- float: left;
-}
-.oo-ui-outlineControlsWidget-items .oo-ui-buttonWidget {
- float: left;
-}
-.oo-ui-outlineControlsWidget-movers {
- float: right;
-}
-.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
- float: right;
-}
-.oo-ui-outlineControlsWidget-items,
-.oo-ui-outlineControlsWidget-movers {
- height: 2em;
- margin: 0.5em;
- padding: 0;
-}
-.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
- width: 1.5em;
- height: 2em;
- margin: 0.5em 0 0.5em 0.5em;
- opacity: 0.2;
-}
-.oo-ui-outlineControlsWidget-items {
- margin-left: 0;
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget {
- z-index: 1;
- min-width: 20em;
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget-handle {
- border: solid 1px rgba(0, 0, 0, 0.1);
- border-radius: 0.25em;
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget-handle:hover {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget.oo-ui-widget-disabled .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator,
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget-empty .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- cursor: default;
- opacity: 0.2;
-}
-.oo-ui-searchWidget-query {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
-}
-.oo-ui-searchWidget-query .oo-ui-textInputWidget {
- width: 100%;
-}
-.oo-ui-searchWidget-results {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- overflow-x: hidden;
- overflow-y: auto;
-}
-.oo-ui-searchWidget-query {
- height: 4em;
- padding: 0 1em;
- box-shadow: 0 0 0.5em rgba(0, 0, 0, 0.2);
-}
-.oo-ui-searchWidget-query .oo-ui-textInputWidget {
- margin: 0.75em 0;
-}
-.oo-ui-searchWidget-results {
- top: 4em;
- padding: 1em;
- line-height: 0;
-}
-.oo-ui-window {
- line-height: 1em;
- /* Content div takes focus when opened, so hide outline */
-}
-.oo-ui-window-frame {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-window-frame > iframe {
- width: 100%;
- height: 100%;
- margin: 0;
- padding: 0;
-}
-.oo-ui-window-content:focus {
- outline: none;
-}
-.oo-ui-window-head,
-.oo-ui-window-foot {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-window-body {
- margin: 0;
- padding: 0;
- background: none;
-}
-.oo-ui-window-overlay {
- position: absolute;
- top: 0;
- left: 0;
-}
-.oo-ui-window-isolated {
- background-color: transparent;
- background-image: none;
- font-family: sans-serif;
- font-size: 0.8em;
-}
-.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;
- overflow: hidden;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-dialog-content > .oo-ui-window-head {
- z-index: 1;
- top: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-head.oo-ui-pendingElement-pending {
- background-image: /* @embed */ url(images/textures/pending.gif);
-}
-.oo-ui-dialog-content > .oo-ui-window-body {
- z-index: 2;
- top: 0;
- bottom: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-foot {
- z-index: 1;
- bottom: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-overlay {
- z-index: 3;
-}
-.oo-ui-dialog-content > .oo-ui-window-body {
- box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
-}
-.oo-ui-messageDialog-actions-horizontal {
- display: table;
- table-layout: fixed;
- width: 100%;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
- display: table-cell;
- width: 1%;
-}
-.oo-ui-messageDialog-actions-vertical {
- display: block;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget {
- position: relative;
- text-align: center;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-buttonElement-button {
- display: block;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labelElement-label {
- position: relative;
- top: auto;
- bottom: auto;
- display: inline;
- white-space: nowrap;
-}
-.oo-ui-messageDialog-content .oo-ui-window-body {
- box-shadow: 0 0 0.33em rgba(0, 0, 0, 0.33);
-}
-.oo-ui-messageDialog-title,
-.oo-ui-messageDialog-message {
- display: block;
- text-align: center;
- padding-top: 0.5em;
-}
-.oo-ui-messageDialog-title {
- font-size: 1.5em;
- line-height: 1em;
- color: #000000;
-}
-.oo-ui-messageDialog-message {
- font-size: 0.9em;
- line-height: 1.25em;
- color: #666666;
-}
-.oo-ui-messageDialog-message-verbose {
- font-size: 1.1em;
- line-height: 1.5em;
- text-align: left;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
- border-right: solid 1px #e5e5e5;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
- border-right-width: 0;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
- border-bottom: solid 1px #e5e5e5;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
- border-bottom-width: 0;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labelElement-label {
- text-align: center;
- line-height: 3.4em;
- padding: 0 2em;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget:hover {
- background-color: rgba(0, 0, 0, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
- background-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
- background-color: rgba(8, 126, 204, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
- background-color: rgba(8, 126, 204, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
- font-weight: bold;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
- background-color: rgba(118, 171, 54, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active {
- background-color: rgba(118, 171, 54, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover {
- background-color: rgba(212, 83, 83, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active {
- background-color: rgba(212, 83, 83, 0.1);
-}
-.oo-ui-processDialog-location {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.oo-ui-processDialog-title {
- display: inline;
- padding: 0;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget {
- white-space: nowrap;
-}
-.oo-ui-processDialog-actions-safe,
-.oo-ui-processDialog-actions-primary {
- position: absolute;
- top: 0;
- bottom: 0;
-}
-.oo-ui-processDialog-actions-safe {
- left: 0;
-}
-.oo-ui-processDialog-actions-primary {
- right: 0;
-}
-.oo-ui-processDialog-errors {
- display: none;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 2;
- overflow-x: hidden;
- overflow-y: auto;
-}
-.oo-ui-processDialog-content .oo-ui-window-head {
- height: 3.4em;
-}
-.oo-ui-processDialog-content .oo-ui-window-body {
- top: 3.4em;
- box-shadow: 0 0 0.33em rgba(0, 0, 0, 0.33);
-}
-.oo-ui-processDialog-navigation {
- position: relative;
- height: 3.4em;
- padding: 0 1em;
-}
-.oo-ui-processDialog-location {
- padding: 0.75em 0;
- height: 1.9em;
- cursor: default;
- text-align: center;
-}
-.oo-ui-processDialog-title {
- font-weight: bold;
- line-height: 1.9em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-buttonElement-button {
- padding-top: 0.75em;
- padding-bottom: 0.75em;
- min-width: 1.9em;
- min-height: 1.9em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-labelElement-label {
- line-height: 1.9em;
- padding: 0 1em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-iconElement-icon,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-iconElement-icon,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-iconElement-icon {
- position: absolute;
- margin-top: -0.125em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-framed {
- margin: 0.75em 0 0.75em 0.75em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
- padding: 0;
- vertical-align: middle;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:hover {
- background-color: rgba(0, 0, 0, 0.05);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:active {
- background-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed {
- margin: 0.75em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
- /* Adjust for border so text aligns with title */
- margin: -1px;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
- background-color: rgba(8, 126, 204, 0.05);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
- background-color: rgba(8, 126, 204, 0.1);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
- font-weight: bold;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
- background-color: rgba(118, 171, 54, 0.05);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active {
- background-color: rgba(118, 171, 54, 0.1);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover {
- background-color: rgba(212, 83, 83, 0.05);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active {
- background-color: rgba(212, 83, 83, 0.1);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- left: 0.5em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-labelElement-label {
- padding-left: 2.25em;
-}
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- right: 0.5em;
-}
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-labelElement-label {
- padding-right: 2.25em;
-}
-.oo-ui-processDialog > .oo-ui-window-frame {
- min-height: 5em;
-}
-.oo-ui-processDialog-errors {
- background-color: rgba(255, 255, 255, 0.9);
- padding: 3em 3em 1.5em 3em;
- text-align: center;
-}
-.oo-ui-processDialog-errors .oo-ui-buttonWidget {
- margin: 2em 1em 2em 1em;
-}
-.oo-ui-processDialog-errors-title {
- font-size: 1.5em;
- color: #000000;
- margin-bottom: 2em;
-}
-.oo-ui-processDialog-error {
- text-align: left;
- margin: 1em;
- padding: 1em;
- border: solid 1px #ff9e9e;
- background-color: #fff7f7;
- border-radius: 0.25em;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog {
- position: fixed;
- width: 0;
- height: 0;
- overflow: hidden;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup {
- width: auto;
- height: auto;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- padding: 1em;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame {
- position: absolute;
- right: 0;
- left: 0;
- margin: auto;
- overflow: hidden;
- max-width: 100%;
- max-height: 100%;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame > iframe {
- width: 100%;
- height: 100%;
-}
-.oo-ui-windowManager-fullscreen > .oo-ui-dialog > .oo-ui-window-frame {
- width: 100%;
- height: 100%;
- top: 0;
- bottom: 0;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog {
- background-color: rgba(255, 255, 255, 0.5);
- opacity: 0;
- -webkit-transition: opacity 250ms ease-in-out;
- -moz-transition: opacity 250ms ease-in-out;
- -ms-transition: opacity 250ms ease-in-out;
- -o-transition: opacity 250ms ease-in-out;
- transition: opacity 250ms ease-in-out;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
- top: 1em;
- bottom: 1em;
- background-color: #ffffff;
- -webkit-transform: scale(0.5);
- -moz-transform: scale(0.5);
- -ms-transform: scale(0.5);
- -o-transform: scale(0.5);
- transform: scale(0.5);
- -webkit-transition: all 250ms ease-in-out;
- -moz-transition: all 250ms ease-in-out;
- -ms-transition: all 250ms ease-in-out;
- -o-transition: all 250ms ease-in-out;
- transition: all 250ms ease-in-out;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
- opacity: 1;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1);
-}
-.oo-ui-windowManager-modal.oo-ui-windowManager-floating > .oo-ui-dialog > .oo-ui-window-frame {
- border: solid 1px #cccccc;
- border-radius: 0.5em;
- box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
-}
diff --git a/resources/lib/oojs-ui/oojs-ui-apex.rtl.css b/resources/lib/oojs-ui/oojs-ui-apex.rtl.css
deleted file mode 100644
index 7dd7b61b..00000000
--- a/resources/lib/oojs-ui/oojs-ui-apex.rtl.css
+++ /dev/null
@@ -1,1929 +0,0 @@
-/*!
- * OOjs UI v0.1.0
- * 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: 2014-09-11T19:39:50Z
- */
-/*
- * Blank theme mixins.
- *
- * Base styles invoke these mixins at the end of their definitions. Override these mixins to add
- * additional rules to the base styles.
- */
-/*
- * Base styles.
- *
- * Themes should include this file after defining their variables and mixins.
- */
-/* @noflip */
-.oo-ui-rtl {
- direction: rtl;
-}
-/* @noflip */
-.oo-ui-ltr {
- direction: ltr;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button {
- 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-buttonElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- display: none;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- display: none;
-}
-.oo-ui-buttonElement.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
- cursor: default;
-}
-.oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
-.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-buttonElement-frameless {
- display: inline-block;
- position: relative;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
- display: inline-block;
- vertical-align: top;
- text-align: center;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- cursor: default;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button {
- color: #333;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-right: 0;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- margin-left: -0.75em;
-}
-.oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
-.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- opacity: 0.8;
- width: 1.9em;
- height: 1.9em;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- /* Don't animate opacities for now, causes wiggling in Chrome (bug 63020) */
- /*.oo-ui-transition(opacity 200ms);*/
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:hover > .oo-ui-iconElement-icon,
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:focus > .oo-ui-iconElement-icon {
- opacity: 1;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
- color: #000;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #333;
- margin-right: 0.25em;
-}
-.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #087ecc;
-}
-.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #76ab36;
-}
-.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #d45353;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #ccc;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
- margin: 0.1em 0;
- padding: 0.2em 0.8em;
- border-radius: 0.3em;
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
- border: 1px #c9c9c9 solid;
- -webkit-transition: border-color 100ms ease-in-out;
- -moz-transition: border-color 100ms ease-in-out;
- -ms-transition: border-color 100ms ease-in-out;
- -o-transition: border-color 100ms ease-in-out;
- transition: border-color 100ms ease-in-out;
- background: #eeeeee;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#ffffff', endColorstr='#dddddd');
- background-image: -webkit-gradient(linear, left top, left 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-buttonElement-framed > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button:focus {
- border-color: #aaa;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- line-height: 1.9em;
-}
-.oo-ui-buttonElement-framed.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
- color: black;
- border-color: #c9c9c9;
- background: #eeeeee;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#dddddd', endColorstr='#ffffff');
- background-image: -webkit-gradient(linear, left top, left 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-buttonElement-framed.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-right: -0.5em;
- margin-left: -0.5em;
-}
-.oo-ui-buttonElement-framed.oo-ui-iconElement.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-right: -0.5em;
- margin-left: 0.3em;
-}
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button {
- border: solid 1px #a6cee1;
- background: #cde7f4;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#eaf4fa', endColorstr='#b0d9ee');
- background-image: -webkit-gradient(linear, left top, left 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-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary > .oo-ui-buttonElement-button:focus {
- border-color: #9dc2d4;
-}
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-primary.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- border: solid 1px #a6cee1;
- background: #cde7f4;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#b0d9ee', endColorstr='#eaf4fa');
- background-image: -webkit-gradient(linear, left top, left 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-buttonElement-framed.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
- border: solid 1px #b8d892;
- background: #daf0be;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f0fbe1', endColorstr='#c3e59a');
- background-image: -webkit-gradient(linear, left top, left 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-buttonElement-framed.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
- border-color: #adcb89;
-}
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-constructive.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-flaggedElement-constructive.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- border: solid 1px #b8d892;
- background: #daf0be;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#c3e59a', endColorstr='#f0fbe1');
- background-image: -webkit-gradient(linear, left top, left 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-buttonElement-framed.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
- color: #d45353;
-}
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- opacity: 0.5;
- box-shadow: none;
- color: #333;
- background: #eee;
- border-color: #ccc;
-}
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button:hover,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button:focus,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button:focus,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button:focus {
- border-color: #ccc;
- box-shadow: none;
-}
-.oo-ui-clippableElement-clippable {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
- overflow-y: hidden;
-}
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
- 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-editable .oo-ui-outlineWidget {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- bottom: 3em;
- overflow-y: auto;
-}
-.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
- position: absolute;
- bottom: 0;
- right: 0;
- left: 0;
-}
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
- padding: 1.5em;
-}
-.oo-ui-bookletLayout-outlinePanel {
- border-left: solid 1px #ddd;
-}
-.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
- box-shadow: 0 0 0.25em rgba(0, 0, 0, 0.25);
-}
-.oo-ui-fieldLayout {
- margin-bottom: 1em;
-}
-.oo-ui-fieldLayout:before,
-.oo-ui-fieldLayout:after {
- content: " ";
- display: table;
-}
-.oo-ui-fieldLayout:after {
- clear: both;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- display: block;
- float: right;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
- display: block;
- float: right;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- text-align: left;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
- display: inline-block;
-}
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
- z-index: 1;
-}
-.oo-ui-fieldLayout:last-child {
- margin-bottom: 0;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- padding-top: 0.5em;
- margin-left: 5%;
- width: 35%;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
- width: 60%;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
- padding: 0.75em 0.5em 0.5em 0.5em;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
- padding: 0.5em 0;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
- padding: 0.5em 0;
-}
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-top: 0.25em;
-}
-.oo-ui-fieldLayout-disabled .oo-ui-labelElement-label {
- color: #ccc;
-}
-.oo-ui-fieldsetLayout {
- position: relative;
- margin: 0;
- padding: 0;
- border: none;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
- display: block;
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-fieldsetLayout.oo-ui-labelElement > .oo-ui-labelElement-label {
- display: inline-block;
-}
-.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout {
- margin-top: 2em;
-}
-.oo-ui-fieldsetLayout > .oo-ui-labelElement-label {
- font-size: 1.5em;
- margin-bottom: 0.5em;
- padding: 0.25em 0;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-labelElement-label {
- padding-right: 1.75em;
- line-height: 1.33em;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
- right: 0;
- top: 0.25em;
- width: 2em;
- height: 2em;
-}
-.oo-ui-gridLayout {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- bottom: 0;
-}
-.oo-ui-panelLayout {
- position: relative;
-}
-.oo-ui-panelLayout-scrollable {
- overflow-y: auto;
-}
-.oo-ui-panelLayout-expanded {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- bottom: 0;
-}
-.oo-ui-panelLayout-padded {
- padding: 1.25em;
-}
-.oo-ui-stackLayout > .oo-ui-panelLayout {
- display: none;
-}
-.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
- display: block;
- position: relative;
-}
-.oo-ui-popupTool .oo-ui-popupWidget-popup,
-.oo-ui-popupTool .oo-ui-popupWidget-anchor {
- z-index: 4;
-}
-.oo-ui-popupTool .oo-ui-popupWidget {
- margin-right: 1.25em;
- font-size: 0.8em;
-}
-.oo-ui-toolGroup {
- display: inline-block;
- vertical-align: middle;
- margin: 0.3em;
- border-radius: 0.25em;
- border: solid 1px transparent;
- -webkit-transition: border-color 300ms ease-in-out;
- -moz-transition: border-color 300ms ease-in-out;
- -ms-transition: border-color 300ms ease-in-out;
- -o-transition: border-color 300ms ease-in-out;
- transition: border-color 300ms ease-in-out;
-}
-.oo-ui-toolGroup-empty {
- display: none;
-}
-.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-toolGroup.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-toolGroup.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-tool-title {
- color: #000;
-}
-.oo-ui-barToolGroup > .oo-ui-iconElement-icon,
-.oo-ui-barToolGroup > .oo-ui-labelElement-label {
- display: none;
-}
-.oo-ui-barToolGroup .oo-ui-tool {
- display: inline-block;
- position: relative;
- vertical-align: top;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link {
- display: block;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- display: block;
-}
-.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-title,
-.oo-ui-barToolGroup .oo-ui-tool-accel {
- display: none;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-link {
- cursor: pointer;
-}
-.oo-ui-barToolGroup .oo-ui-tool {
- margin: -1px -1px -1px 0;
- border: solid 1px transparent;
-}
-.oo-ui-barToolGroup .oo-ui-tool:first-child {
- border-top-right-radius: 0.25em;
- border-bottom-right-radius: 0.25em;
-}
-.oo-ui-barToolGroup .oo-ui-tool:last-child {
- margin-left: -1px;
- border-top-left-radius: 0.25em;
- border-bottom-left-radius: 0.25em;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link {
- height: 1.5em;
- padding: 0.25em;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- height: 1.5em;
- width: 1.5em;
- opacity: 0.8;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-active.oo-ui-widget-enabled {
- border-color: rgba(0, 0, 0, 0.2);
- box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
- background: #f8fbfd;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f1f7fb', endColorstr='#ffffff');
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f1f7fb), color-stop(100%, #ffffff));
- background-image: -webkit-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -moz-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -ms-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
- border-right-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.8;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool.oo-ui-widget-enabled:hover .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 1;
-}
-.oo-ui-barToolGroup.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-popupToolGroup {
- position: relative;
- height: 2em;
- min-width: 2.5em;
-}
-.oo-ui-popupToolGroup-handle {
- display: block;
- cursor: pointer;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-popupToolGroup.oo-ui-widget-disabled .oo-ui-popupToolGroup-handle {
- cursor: default;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
- display: none;
- position: absolute;
- z-index: 4;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconElement-icon {
- background-repeat: no-repeat;
- background-position: center center;
-}
-.oo-ui-popupToolGroup-active.oo-ui-widget-enabled > .oo-ui-toolGroup-tools {
- display: block;
-}
-.oo-ui-popupToolGroup-left > .oo-ui-toolGroup-tools {
- right: 0;
-}
-.oo-ui-popupToolGroup-right > .oo-ui-toolGroup-tools {
- left: 0;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-accel {
- display: none;
-}
-.oo-ui-popupToolGroup.oo-ui-indicatorElement.oo-ui-iconElement {
- min-width: 3.5em;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- top: 0;
- width: 2em;
- height: 2em;
- opacity: 0.8;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
- left: 0;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- right: 0.25em;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- line-height: 2.6em;
- font-size: 0.8em;
- margin: 0 1em;
-}
-.oo-ui-popupToolGroup-header {
- line-height: 2.6em;
- font-size: 0.8em;
- margin: 0 0.6em;
- font-weight: bold;
-}
-.oo-ui-popupToolGroup-active.oo-ui-widget-enabled {
- border-bottom-right-radius: 0;
- border-bottom-left-radius: 0;
- box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
- background: #f8fbfd;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f1f7fb', endColorstr='#ffffff');
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f1f7fb), color-stop(100%, #ffffff));
- background-image: -webkit-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -moz-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -ms-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
-}
-.oo-ui-popupToolGroup.oo-ui-iconElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-right: 3em;
-}
-.oo-ui-popupToolGroup.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-left: 2.25em;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
- top: 2em;
- margin: 0 -1px;
- border: solid 1px #ccc;
- background-color: white;
- box-shadow: 0 0.25em 1em rgba(0, 0, 0, 0.25);
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- height: 2em;
- width: 2em;
- margin-left: 0.25em;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
- line-height: 2em;
- font-size: 0.8em;
-}
-.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;
-}
-.oo-ui-listToolGroup .oo-ui-tool-link {
- display: block;
- cursor: pointer;
- white-space: nowrap;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
-.oo-ui-listToolGroup .oo-ui-toolGroup-tools {
- padding: 0.25em;
-}
-.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-listToolGroup .oo-ui-tool {
- border: solid 1px transparent;
- margin: -1px 0;
-}
-.oo-ui-listToolGroup .oo-ui-tool-link {
- padding-left: 0.5em;
-}
-.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled {
- border-color: rgba(0, 0, 0, 0.1);
- box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
- background: #f8fbfd;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#f1f7fb', endColorstr='#ffffff');
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #f1f7fb), color-stop(100%, #ffffff));
- background-image: -webkit-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -moz-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -ms-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
- background-image: linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
-}
-.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
- border-top-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.8;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 1;
-}
-.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-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-listToolGroup.oo-ui-widget-disabled {
- color: #ccc;
-}
-.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
-.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-menuToolGroup {
- border-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-menuToolGroup .oo-ui-tool {
- display: block;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-link {
- display: block;
- cursor: pointer;
- white-space: nowrap;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-image: none;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-image: /* @embed */ url(images/icons/check.svg);
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
-.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
- min-width: 8em;
-}
-.oo-ui-menuToolGroup .oo-ui-toolGroup-tools {
- padding: 0.25em 0 0.25em 0;
-}
-.oo-ui-menuToolGroup.oo-ui-widget-enabled: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-tool-link {
- padding: 0 0.25em 0 1em;
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
- background-color: #e1f3ff;
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
- color: #ccc;
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-menuToolGroup.oo-ui-widget-disabled {
- color: #ccc;
- border-color: rgba(0, 0, 0, 0.05);
-}
-.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
-.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
- opacity: 0.2;
-}
-.oo-ui-toolbar {
- clear: both;
-}
-.oo-ui-toolbar-bar {
- line-height: 1em;
-}
-.oo-ui-toolbar-actions {
- float: left;
-}
-.oo-ui-toolbar-tools {
- display: inline;
-}
-.oo-ui-toolbar-tools,
-.oo-ui-toolbar-actions,
-.oo-ui-toolbar-shadow {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-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 {
- background-position: right top;
- background-repeat: repeat-x;
- position: absolute;
- width: 100%;
- pointer-events: none;
-}
-.oo-ui-toolbar-bar {
- border-bottom: solid 1px #ccc;
- background: #f8fbfd;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#ffffff', endColorstr='#f1f7fb');
- background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #f1f7fb));
- background-image: -webkit-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
- background-image: -moz-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
- background-image: -ms-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
- background-image: -o-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
- background-image: linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
-}
-.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
- border: none;
- background: none;
-}
-.oo-ui-toolbar-shadow {
- background-image: /* @embed */ url(images/toolbar-shadow.png);
- bottom: -9px;
- height: 9px;
- opacity: 0.125;
- -webkit-transition: opacity 500ms ease-in-out;
- -moz-transition: opacity 500ms ease-in-out;
- -ms-transition: opacity 500ms ease-in-out;
- -o-transition: opacity 500ms ease-in-out;
- transition: opacity 500ms ease-in-out;
-}
-.oo-ui-optionWidget {
- position: relative;
- display: block;
- cursor: pointer;
- padding: 0.5em 3em 0.5em 2em;
- border: none;
-}
-.oo-ui-optionWidget.oo-ui-widget-disabled {
- cursor: default;
-}
-.oo-ui-optionWidget .oo-ui-labelElement-label {
- display: block;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
-}
-.oo-ui-optionWidget-highlighted {
- background-color: #e1f3ff;
-}
-.oo-ui-optionWidget .oo-ui-labelElement-label {
- line-height: 1.5em;
-}
-.oo-ui-selectWidget-depressed .oo-ui-optionWidget-selected {
- background-color: #a7dcff;
-}
-.oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed {
- background-color: #a7dcff;
-}
-.oo-ui-optionWidget.oo-ui-widget-disabled {
- color: #ccc;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon,
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- position: absolute;
- background-repeat: no-repeat;
- background-position: center center;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon,
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- top: 50%;
- width: 2em;
- height: 2em;
- margin-top: -1em;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon {
- right: 0.5em;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- left: 0.5em;
-}
-.oo-ui-buttonSelectWidget {
- display: inline-block;
- white-space: nowrap;
- border-radius: 0.3em;
-}
-.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-right: -1px;
-}
-.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonElement-button {
- border-bottom-right-radius: 0.3em;
- border-top-right-radius: 0.3em;
- margin-right: 0;
-}
-.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonElement-button {
- border-bottom-left-radius: 0.3em;
- border-top-left-radius: 0.3em;
-}
-.oo-ui-buttonOptionWidget {
- display: inline-block;
- padding: 0;
- background-color: transparent;
-}
-.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- position: relative;
-}
-.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
-.oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- position: static;
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- height: 1.9em;
-}
-.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
-.oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- height: 1.9em;
- margin-top: 0;
-}
-.oo-ui-buttonOptionWidget.oo-ui-optionWidget-selected,
-.oo-ui-buttonOptionWidget.oo-ui-optionWidget-pressed,
-.oo-ui-buttonOptionWidget.oo-ui-optionWidget-highlighted {
- background-color: transparent;
-}
-.oo-ui-labelWidget {
- display: inline-block;
- padding: 0.5em 0;
-}
-.oo-ui-iconWidget {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- line-height: 2.5em;
- height: 1.9em;
- width: 1.9em;
- opacity: 0.8;
-}
-.oo-ui-iconWidget.oo-ui-widget-disabled {
- opacity: 0.2;
-}
-.oo-ui-indicatorWidget {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- line-height: 2.5em;
- height: 1.9em;
- width: 1.9em;
- opacity: 0.8;
-}
-.oo-ui-indicatorWidget.oo-ui-widget-disabled {
- opacity: 0.2;
-}
-.oo-ui-buttonWidget {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonGroupWidget {
- display: inline-block;
- white-space: nowrap;
- border-radius: 0.3em;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-bottom: -1px;
- margin-right: -1px;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:first-child .oo-ui-buttonElement-button {
- border-bottom-right-radius: 0.3em;
- border-top-right-radius: 0.3em;
- margin-right: 0;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:last-child .oo-ui-buttonElement-button {
- border-bottom-left-radius: 0.3em;
- border-top-left-radius: 0.3em;
-}
-.oo-ui-toggleSwitchWidget {
- position: relative;
- display: inline-block;
- vertical-align: middle;
- overflow: hidden;
- 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);
- height: 2em;
- width: 4em;
- border-radius: 1em;
- box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #ddd;
- border: solid 1px #ccc;
- background: #eeeeee;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#dddddd', endColorstr='#ffffff');
- background-image: -webkit-gradient(linear, left top, left 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 {
- cursor: default;
-}
-.oo-ui-toggleSwitchWidget-grip {
- position: absolute;
- display: block;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
- display: none;
-}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
- opacity: 0.5;
-}
-.oo-ui-toggleSwitchWidget-grip {
- top: 0.25em;
- right: 0.25em;
- width: 1.5em;
- height: 1.5em;
- margin-top: -1px;
- border-radius: 1em;
- box-shadow: 0 0.1em 0.25em rgba(0, 0, 0, 0.1);
- border: 1px #c9c9c9 solid;
- -webkit-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
- -moz-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
- -ms-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
- -o-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
- transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
- background: #eeeeee;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#ffffff', endColorstr='#dddddd');
- background-image: -webkit-gradient(linear, left top, left 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.oo-ui-widget-enabled:hover,
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover .oo-ui-toggleSwitchWidget-grip {
- border-color: #aaa;
-}
-.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
- border-radius: 1em;
- box-shadow: inset 0 1px 4px 0 rgba(0, 0, 0, 0.07);
- -webkit-transition: opacity 200ms ease-in-out;
- -moz-transition: opacity 200ms ease-in-out;
- -ms-transition: opacity 200ms ease-in-out;
- -o-transition: opacity 200ms ease-in-out;
- transition: opacity 200ms ease-in-out;
- background: #cde7f4;
- filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0, startColorstr='#b0d9ee', endColorstr='#eaf4fa');
- background-image: -webkit-gradient(linear, left top, left 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-glow {
- opacity: 1;
-}
-.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
- right: 2.25em;
- margin-right: -2px;
-}
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
- display: block;
- opacity: 0;
-}
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
- right: 0.25em;
- margin-right: 0;
-}
-.oo-ui-popupWidget-popup {
- position: absolute;
- overflow: hidden;
- z-index: 1;
-}
-.oo-ui-popupWidget-anchor {
- display: none;
- z-index: 1;
-}
-.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
- display: block;
- position: absolute;
- background-repeat: no-repeat;
-}
-.oo-ui-popupWidget-head {
- -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: left;
-}
-.oo-ui-popupWidget-head .oo-ui-labelElement-label {
- float: right;
- cursor: default;
-}
-.oo-ui-popupWidget-body {
- clear: both;
- overflow: hidden;
-}
-.oo-ui-popupWidget-popup {
- 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-anchored .oo-ui-popupWidget-popup {
- margin-top: 7px;
-}
-.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
- width: 15px;
- height: 8px;
- margin-right: -7px;
- background-image: /* @embed */ url(images/anchor.svg);
-}
-.oo-ui-popupWidget-transitioning .oo-ui-popupWidget-popup {
- -webkit-transition: width 100ms ease-in-out, height 100ms ease-in-out, right 100ms ease-in-out;
- -moz-transition: width 100ms ease-in-out, height 100ms ease-in-out, right 100ms ease-in-out;
- -ms-transition: width 100ms ease-in-out, height 100ms ease-in-out, right 100ms ease-in-out;
- -o-transition: width 100ms ease-in-out, height 100ms ease-in-out, right 100ms ease-in-out;
- transition: width 100ms ease-in-out, height 100ms ease-in-out, right 100ms ease-in-out;
-}
-.oo-ui-popupWidget-head {
- height: 2.5em;
-}
-.oo-ui-popupWidget-head .oo-ui-buttonWidget {
- margin: 0.25em;
-}
-.oo-ui-popupWidget-head .oo-ui-labelElement-label {
- margin: 0.75em 1em;
-}
-.oo-ui-popupWidget-body {
- box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
-}
-.oo-ui-popupWidget-body-padded {
- padding: 0 1em;
-}
-.oo-ui-popupButtonWidget {
- position: relative;
-}
-.oo-ui-popupButtonWidget .oo-ui-popupWidget {
- position: absolute;
- right: 1em;
- cursor: auto;
-}
-.oo-ui-textInputWidget {
- position: relative;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- width: 20em;
-}
-.oo-ui-textInputWidget input,
-.oo-ui-textInputWidget textarea {
- display: inline-block;
- width: 100%;
- resize: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-textInputWidget > .oo-ui-iconElement-icon,
-.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator {
- position: absolute;
- top: 0;
- height: 100%;
- background-repeat: no-repeat;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-textInputWidget > .oo-ui-iconElement-icon {
- right: 0;
-}
-.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator {
- left: 0;
-}
-.oo-ui-textInputWidget input,
-.oo-ui-textInputWidget textarea {
- padding: 0.5em;
- 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;
- border-radius: 0.25em;
- -webkit-transition: border-color 200ms, box-shadow 200ms;
- -moz-transition: border-color 200ms, box-shadow 200ms;
- -ms-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-decorated input,
-.oo-ui-textInputWidget-decorated textarea {
- padding-right: 2em;
-}
-.oo-ui-textInputWidget-icon {
- width: 2em;
-}
-.oo-ui-textInputWidget.oo-ui-widget-enabled input:focus,
-.oo-ui-textInputWidget.oo-ui-widget-enabled 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-textInputWidget-pending input,
-.oo-ui-textInputWidget-pending textarea {
- background-color: transparent;
-}
-.oo-ui-textInputWidget.oo-ui-widget-disabled input,
-.oo-ui-textInputWidget.oo-ui-widget-disabled input:focus,
-.oo-ui-textInputWidget.oo-ui-widget-disabled textarea,
-.oo-ui-textInputWidget.oo-ui-widget-disabled textarea:focus {
- color: #ccc;
- text-shadow: 0 1px 1px #fff;
- border-color: #ddd;
- background-color: #f3f3f3;
-}
-.oo-ui-textInputWidget .oo-ui-iconElement-icon,
-.oo-ui-textInputWidget .oo-ui-indicatorElement-indicator {
- opacity: 0.8;
-}
-.oo-ui-textInputWidget.oo-ui-iconElement input,
-.oo-ui-textInputWidget.oo-ui-iconElement textarea {
- padding-right: 2em;
-}
-.oo-ui-textInputWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- width: 2em;
- background-position: left center;
-}
-.oo-ui-textInputWidget.oo-ui-indicatorElement input,
-.oo-ui-textInputWidget.oo-ui-indicatorElement textarea {
- padding-left: 1.5em;
-}
-.oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- width: 1.5em;
- background-position: right center;
-}
-.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 {
- position: relative;
-}
-.oo-ui-menuItemWidget .oo-ui-iconElement-icon {
- display: none;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
- background-color: transparent;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected .oo-ui-iconElement-icon {
- display: block;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
- background-color: transparent;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-highlighted,
-.oo-ui-menuItemWidget.oo-ui-optionWidget-highlighted.oo-ui-optionWidget-selected {
- background-color: #e1f3ff;
-}
-.oo-ui-menuSectionItemWidget {
- cursor: default;
- padding: 0.33em 0.75em;
- color: #888;
-}
-.oo-ui-inlineMenuWidget {
- position: relative;
- display: inline-block;
- margin: 0.25em 0;
- min-width: 20em;
-}
-.oo-ui-inlineMenuWidget-handle {
- width: 100%;
- display: inline-block;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-inlineMenuWidget .oo-ui-menuWidget {
- z-index: 1;
- width: 100%;
-}
-.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-inlineMenuWidget-handle {
- cursor: default;
-}
-.oo-ui-inlineMenuWidget-handle {
- height: 2.5em;
- border: solid 1px rgba(0, 0, 0, 0.1);
- border-radius: 0.25em;
-}
-.oo-ui-inlineMenuWidget-handle:hover {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator {
- left: 0;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- right: 0.25em;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- line-height: 2.5em;
- margin: 0 0.5em;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- top: 0;
- width: 2.5em;
- height: 2.5em;
- opacity: 0.8;
-}
-.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-inlineMenuWidget-handle {
- color: #ccc;
- text-shadow: 0 1px 1px #fff;
- border-color: #ddd;
- background-color: #f3f3f3;
-}
-.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
- opacity: 0.2;
-}
-.oo-ui-inlineMenuWidget.oo-ui-iconElement .oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- margin-right: 3em;
-}
-.oo-ui-inlineMenuWidget.oo-ui-indicatorElement .oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- margin-left: 2em;
-}
-.oo-ui-outlineItemWidget {
- position: relative;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- font-size: 1.1em;
- padding: 0.75em;
-}
-.oo-ui-outlineItemWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
- padding-left: 1.5em;
-}
-.oo-ui-outlineItemWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- opacity: 0.5;
-}
-.oo-ui-outlineItemWidget-level-0 {
- padding-right: 3.5em;
-}
-.oo-ui-outlineItemWidget-level-0 .oo-ui-iconElement-icon {
- right: 1em;
-}
-.oo-ui-outlineItemWidget-level-1 {
- padding-right: 5em;
-}
-.oo-ui-outlineItemWidget-level-1 .oo-ui-iconElement-icon {
- right: 2.5em;
-}
-.oo-ui-outlineItemWidget-level-2 {
- padding-right: 6.5em;
-}
-.oo-ui-outlineItemWidget-level-2 .oo-ui-iconElement-icon {
- right: 4em;
-}
-.oo-ui-selectWidget-depressed .oo-ui-outlineItemWidget.oo-ui-optionWidget-selected {
- background-color: #a7dcff;
- text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
-}
-.oo-ui-outlineItemWidget.oo-ui-flaggedElement-important {
- font-weight: bold;
-}
-.oo-ui-outlineItemWidget.oo-ui-flaggedElement-placeholder {
- font-style: italic;
-}
-.oo-ui-outlineItemWidget.oo-ui-flaggedElement-empty .oo-ui-iconElement-icon {
- opacity: 0.5;
-}
-.oo-ui-outlineItemWidget.oo-ui-flaggedElement-empty .oo-ui-labelElement-label {
- color: #777;
-}
-.oo-ui-outlineControlsWidget {
- height: 3em;
- background-color: #fff;
-}
-.oo-ui-outlineControlsWidget-items,
-.oo-ui-outlineControlsWidget-movers {
- float: right;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
- float: right;
- background-position: left center;
- background-repeat: no-repeat;
-}
-.oo-ui-outlineControlsWidget-items {
- float: right;
-}
-.oo-ui-outlineControlsWidget-items .oo-ui-buttonWidget {
- float: right;
-}
-.oo-ui-outlineControlsWidget-movers {
- float: left;
-}
-.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
- float: left;
-}
-.oo-ui-outlineControlsWidget-items,
-.oo-ui-outlineControlsWidget-movers {
- height: 2em;
- margin: 0.5em;
- padding: 0;
-}
-.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
- width: 1.5em;
- height: 2em;
- margin: 0.5em 0.5em 0.5em 0;
- opacity: 0.2;
-}
-.oo-ui-outlineControlsWidget-items {
- margin-right: 0;
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget {
- z-index: 1;
- min-width: 20em;
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget-handle {
- border: solid 1px rgba(0, 0, 0, 0.1);
- border-radius: 0.25em;
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget-handle:hover {
- border-color: rgba(0, 0, 0, 0.2);
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget.oo-ui-widget-disabled .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator,
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget-empty .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- cursor: default;
- opacity: 0.2;
-}
-.oo-ui-searchWidget-query {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
-}
-.oo-ui-searchWidget-query .oo-ui-textInputWidget {
- width: 100%;
-}
-.oo-ui-searchWidget-results {
- position: absolute;
- bottom: 0;
- right: 0;
- left: 0;
- overflow-x: hidden;
- overflow-y: auto;
-}
-.oo-ui-searchWidget-query {
- height: 4em;
- padding: 0 1em;
- box-shadow: 0 0 0.5em rgba(0, 0, 0, 0.2);
-}
-.oo-ui-searchWidget-query .oo-ui-textInputWidget {
- margin: 0.75em 0;
-}
-.oo-ui-searchWidget-results {
- top: 4em;
- padding: 1em;
- line-height: 0;
-}
-.oo-ui-window {
- line-height: 1em;
- /* Content div takes focus when opened, so hide outline */
-}
-.oo-ui-window-frame {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-window-frame > iframe {
- width: 100%;
- height: 100%;
- margin: 0;
- padding: 0;
-}
-.oo-ui-window-content:focus {
- outline: none;
-}
-.oo-ui-window-head,
-.oo-ui-window-foot {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-window-body {
- margin: 0;
- padding: 0;
- background: none;
-}
-.oo-ui-window-overlay {
- position: absolute;
- top: 0;
- right: 0;
-}
-.oo-ui-window-isolated {
- background-color: transparent;
- background-image: none;
- font-family: sans-serif;
- font-size: 0.8em;
-}
-.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;
- right: 0;
- left: 0;
- overflow: hidden;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-dialog-content > .oo-ui-window-head {
- z-index: 1;
- top: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-body {
- z-index: 2;
- top: 0;
- bottom: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-foot {
- z-index: 1;
- bottom: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-overlay {
- z-index: 3;
-}
-.oo-ui-dialog-content > .oo-ui-window-body {
- box-shadow: 0 0 0.66em rgba(0, 0, 0, 0.25);
-}
-.oo-ui-messageDialog-actions-horizontal {
- display: table;
- table-layout: fixed;
- width: 100%;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
- display: table-cell;
- width: 1%;
-}
-.oo-ui-messageDialog-actions-vertical {
- display: block;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget {
- position: relative;
- text-align: center;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-buttonElement-button {
- display: block;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labelElement-label {
- position: relative;
- top: auto;
- bottom: auto;
- display: inline;
- white-space: nowrap;
-}
-.oo-ui-messageDialog-content .oo-ui-window-body {
- box-shadow: 0 0 0.33em rgba(0, 0, 0, 0.33);
-}
-.oo-ui-messageDialog-title,
-.oo-ui-messageDialog-message {
- display: block;
- text-align: center;
- padding-top: 0.5em;
-}
-.oo-ui-messageDialog-title {
- font-size: 1.5em;
- line-height: 1em;
- color: #000;
-}
-.oo-ui-messageDialog-message {
- font-size: 0.9em;
- line-height: 1.25em;
- color: #666;
-}
-.oo-ui-messageDialog-message-verbose {
- font-size: 1.1em;
- line-height: 1.5em;
- text-align: right;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
- border-left: solid 1px #e5e5e5;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
- border-left-width: 0;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
- border-bottom: solid 1px #e5e5e5;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
- border-bottom-width: 0;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labelElement-label {
- text-align: center;
- line-height: 3.4em;
- padding: 0 2em;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget:hover {
- background-color: rgba(0, 0, 0, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
- background-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
- background-color: rgba(8, 126, 204, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
- background-color: rgba(8, 126, 204, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
- font-weight: bold;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
- background-color: rgba(118, 171, 54, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active {
- background-color: rgba(118, 171, 54, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover {
- background-color: rgba(212, 83, 83, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active {
- background-color: rgba(212, 83, 83, 0.1);
-}
-.oo-ui-processDialog-location {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.oo-ui-processDialog-title {
- display: inline;
- padding: 0;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget {
- white-space: nowrap;
-}
-.oo-ui-processDialog-actions-safe,
-.oo-ui-processDialog-actions-primary {
- position: absolute;
- top: 0;
- bottom: 0;
-}
-.oo-ui-processDialog-actions-safe {
- right: 0;
-}
-.oo-ui-processDialog-actions-primary {
- left: 0;
-}
-.oo-ui-processDialog-errors {
- display: none;
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- bottom: 0;
- z-index: 2;
- overflow-x: hidden;
- overflow-y: auto;
-}
-.oo-ui-processDialog-content .oo-ui-window-head {
- height: 3.4em;
-}
-.oo-ui-processDialog-content .oo-ui-window-body {
- top: 3.4em;
- box-shadow: 0 0 0.33em rgba(0, 0, 0, 0.33);
-}
-.oo-ui-processDialog-navigation {
- position: relative;
- height: 3.4em;
- padding: 0 1em;
-}
-.oo-ui-processDialog-location {
- padding: 0.75em 0;
- height: 1.9em;
- cursor: default;
- text-align: center;
-}
-.oo-ui-processDialog-title {
- font-weight: bold;
- line-height: 1.9em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-buttonElement-button {
- padding-top: 0.75em;
- padding-bottom: 0.75em;
- min-width: 1.9em;
- min-height: 1.9em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-labelElement-label {
- line-height: 1.9em;
- padding: 0 1em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-iconElement-icon,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-iconElement-icon,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-iconElement-icon {
- position: absolute;
- margin-top: -0.125em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-framed {
- margin: 0.75em 0.75em 0.75em 0;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
- padding: 0;
- vertical-align: middle;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:hover {
- background-color: rgba(0, 0, 0, 0.05);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:active {
- background-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed {
- margin: 0.75em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
- /* Adjust for border so text aligns with title */
- margin: -1px;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
- background-color: rgba(8, 126, 204, 0.05);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
- background-color: rgba(8, 126, 204, 0.1);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
- font-weight: bold;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
- background-color: rgba(118, 171, 54, 0.05);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active {
- background-color: rgba(118, 171, 54, 0.1);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover {
- background-color: rgba(212, 83, 83, 0.05);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active {
- background-color: rgba(212, 83, 83, 0.1);
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- right: 0.5em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-labelElement-label {
- padding-right: 2.25em;
-}
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- left: 0.5em;
-}
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-labelElement-label {
- padding-left: 2.25em;
-}
-.oo-ui-processDialog > .oo-ui-window-frame {
- min-height: 5em;
-}
-.oo-ui-processDialog-errors {
- background-color: rgba(255, 255, 255, 0.9);
- padding: 3em 3em 1.5em 3em;
- text-align: center;
-}
-.oo-ui-processDialog-errors .oo-ui-buttonWidget {
- margin: 2em 1em 2em 1em;
-}
-.oo-ui-processDialog-errors-title {
- font-size: 1.5em;
- color: #000;
- margin-bottom: 2em;
-}
-.oo-ui-processDialog-error {
- text-align: right;
- margin: 1em;
- padding: 1em;
- border: solid 1px #ff9e9e;
- background-color: #fff7f7;
- border-radius: 0.25em;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog {
- position: fixed;
- width: 0;
- height: 0;
- overflow: hidden;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup {
- width: auto;
- height: auto;
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
- padding: 1em;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame {
- position: fixed;
- left: 0;
- right: 0;
- margin: auto;
- overflow: hidden;
- max-width: 100%;
- max-height: 100%;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame > iframe {
- width: 100%;
- height: 100%;
-}
-.oo-ui-windowManager-fullscreen > .oo-ui-dialog > .oo-ui-window-frame {
- width: 100%;
- height: 100%;
- top: 0;
- bottom: 0;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog {
- background-color: rgba(255, 255, 255, 0.5);
- opacity: 0;
- -webkit-transition: opacity 250ms ease-in-out;
- -moz-transition: opacity 250ms ease-in-out;
- -ms-transition: opacity 250ms ease-in-out;
- -o-transition: opacity 250ms ease-in-out;
- transition: opacity 250ms ease-in-out;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
- top: 1em;
- bottom: 1em;
- background-color: #fff;
- -webkit-transform: scale(0.5);
- -moz-transform: scale(0.5);
- -ms-transform: scale(0.5);
- -o-transform: scale(0.5);
- transform: scale(0.5);
- -webkit-transition: all 250ms ease-in-out;
- -moz-transition: all 250ms ease-in-out;
- -ms-transition: all 250ms ease-in-out;
- -o-transition: all 250ms ease-in-out;
- transition: all 250ms ease-in-out;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
- opacity: 1;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
- -webkit-transform: scale(1);
- -moz-transform: scale(1);
- -ms-transform: scale(1);
- -o-transform: scale(1);
- transform: scale(1);
-}
-.oo-ui-windowManager-modal.oo-ui-windowManager-floating > .oo-ui-dialog > .oo-ui-window-frame {
- border: solid 1px #ccc;
- border-radius: 0.5em;
- box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
-}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-alerts.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-alerts.css
new file mode 100644
index 00000000..545c64d0
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-alerts.css
@@ -0,0 +1,64 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-bell {
+ background-image: url("themes/mediawiki/images/icons/bell.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bell.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bell.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bell.png");
+}
+.oo-ui-icon-bellOn {
+ background-image: url("themes/mediawiki/images/icons/bellOn-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bellOn-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bellOn-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bellOn-ltr.png");
+}
+.oo-ui-icon-eye {
+ background-image: url("themes/mediawiki/images/icons/eye.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/eye.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/eye.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/eye.png");
+}
+.oo-ui-icon-eyeClosed {
+ background-image: url("themes/mediawiki/images/icons/eyeClosed.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/eyeClosed.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/eyeClosed.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/eyeClosed.png");
+}
+.oo-ui-icon-message {
+ background-image: url("themes/mediawiki/images/icons/message-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/message-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/message-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/message-ltr.png");
+}
+.oo-ui-icon-signature {
+ background-image: url("themes/mediawiki/images/icons/signature-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/signature-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/signature-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/signature-ltr.png");
+}
+.oo-ui-icon-speechBubble {
+ background-image: url("themes/mediawiki/images/icons/speechBubble-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/speechBubble-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/speechBubble-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/speechBubble-ltr.png");
+}
+.oo-ui-icon-speechBubbleAdd {
+ background-image: url("themes/mediawiki/images/icons/speechBubbleAdd-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/speechBubbleAdd-ltr.png");
+}
+.oo-ui-icon-speechBubbles {
+ background-image: url("themes/mediawiki/images/icons/speechBubbles-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/speechBubbles-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/speechBubbles-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/speechBubbles-ltr.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-content.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-content.css
new file mode 100644
index 00000000..acd14255
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-content.css
@@ -0,0 +1,76 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-article {
+ background-image: url("themes/mediawiki/images/icons/article-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/article-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/article-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/article-ltr.png");
+}
+.oo-ui-icon-articleCheck {
+ background-image: url("themes/mediawiki/images/icons/articleCheck-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/articleCheck-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/articleCheck-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/articleCheck-ltr.png");
+}
+.oo-ui-icon-articleSearch {
+ background-image: url("themes/mediawiki/images/icons/articleSearch-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/articleSearch-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/articleSearch-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/articleSearch-ltr.png");
+}
+.oo-ui-icon-book {
+ background-image: url("themes/mediawiki/images/icons/book-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/book-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/book-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/book-ltr.png");
+}
+.oo-ui-icon-citeArticle {
+ background-image: url("themes/mediawiki/images/icons/citeArticle-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/citeArticle-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/citeArticle-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/citeArticle-ltr.png");
+}
+.oo-ui-icon-die {
+ background-image: url("themes/mediawiki/images/icons/die-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/die-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/die-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/die-ltr.png");
+}
+.oo-ui-icon-download {
+ background-image: url("themes/mediawiki/images/icons/download-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/download-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/download-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/download-ltr.png");
+}
+.oo-ui-icon-folderPlaceholder {
+ background-image: url("themes/mediawiki/images/icons/folderPlaceholder-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/folderPlaceholder-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/folderPlaceholder-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/folderPlaceholder-ltr.png");
+}
+.oo-ui-icon-journal {
+ background-image: url("themes/mediawiki/images/icons/journal-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/journal-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/journal-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/journal-ltr.png");
+}
+.oo-ui-icon-newspaper {
+ background-image: url("themes/mediawiki/images/icons/newspaper-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/newspaper-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/newspaper-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/newspaper-ltr.png");
+}
+.oo-ui-icon-upload {
+ background-image: url("themes/mediawiki/images/icons/upload-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/upload-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/upload-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/upload-ltr.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-advanced.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-advanced.css
new file mode 100644
index 00000000..5f4cb821
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-advanced.css
@@ -0,0 +1,166 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-alignCentre {
+ background-image: url("themes/mediawiki/images/icons/align-center.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/align-center.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/align-center.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/align-center.png");
+}
+.oo-ui-icon-alignLeft {
+ background-image: url("themes/mediawiki/images/icons/align-float-left.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/align-float-left.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/align-float-left.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/align-float-left.png");
+}
+.oo-ui-icon-alignRight {
+ background-image: url("themes/mediawiki/images/icons/align-float-right.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/align-float-right.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/align-float-right.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/align-float-right.png");
+}
+.oo-ui-icon-find {
+ background-image: url("themes/mediawiki/images/icons/find-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/find-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/find-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/find-ltr.png");
+}
+.oo-ui-icon-insert {
+ background-image: url("themes/mediawiki/images/icons/insert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/insert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/insert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/insert.png");
+}
+.oo-ui-icon-layout {
+ background-image: url("themes/mediawiki/images/icons/layout-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/layout-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/layout-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/layout-ltr.png");
+}
+.oo-ui-icon-newline {
+ background-image: url("themes/mediawiki/images/icons/newline-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/newline-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/newline-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/newline-ltr.png");
+}
+.oo-ui-icon-redirect {
+ background-image: url("themes/mediawiki/images/icons/redirect-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/redirect-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/redirect-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/redirect-ltr.png");
+}
+.oo-ui-icon-noWikiText {
+ background-image: url("themes/mediawiki/images/icons/noWikiText-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/noWikiText-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/noWikiText-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/noWikiText-ltr.png");
+}
+.oo-ui-icon-outline {
+ background-image: url("themes/mediawiki/images/icons/outline-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/outline-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/outline-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/outline-ltr.png");
+}
+.oo-ui-icon-puzzle {
+ background-image: url("themes/mediawiki/images/icons/puzzle-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/puzzle-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/puzzle-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/puzzle-ltr.png");
+}
+.oo-ui-icon-quotes {
+ background-image: url("themes/mediawiki/images/icons/quotes-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/quotes-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/quotes-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/quotes-ltr.png");
+}
+.oo-ui-icon-quotesAdd {
+ background-image: url("themes/mediawiki/images/icons/quotesAdd-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/quotesAdd-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/quotesAdd-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/quotesAdd-ltr.png");
+}
+.oo-ui-icon-searchCaseSensitive {
+ background-image: url("themes/mediawiki/images/icons/case-sensitive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/case-sensitive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/case-sensitive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/case-sensitive.png");
+}
+.oo-ui-icon-searchRegularExpression {
+ background-image: url("themes/mediawiki/images/icons/regular-expression.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/regular-expression.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/regular-expression.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/regular-expression.png");
+}
+.oo-ui-icon-specialCharacter {
+ background-image: url("themes/mediawiki/images/icons/specialCharacter.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/specialCharacter.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/specialCharacter.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/specialCharacter.png");
+}
+.oo-ui-icon-table {
+ background-image: url("themes/mediawiki/images/icons/table.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/table.png");
+}
+.oo-ui-icon-tableAddColumnAfter {
+ background-image: url("themes/mediawiki/images/icons/table-insert-column-rtl.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-insert-column-rtl.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-insert-column-rtl.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/table-insert-column-rtl.png");
+}
+.oo-ui-icon-tableAddColumnBefore {
+ background-image: url("themes/mediawiki/images/icons/table-insert-column-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-insert-column-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-insert-column-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/table-insert-column-ltr.png");
+}
+.oo-ui-icon-tableAddRowAfter {
+ background-image: url("themes/mediawiki/images/icons/table-insert-row-after.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-insert-row-after.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-insert-row-after.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/table-insert-row-after.png");
+}
+.oo-ui-icon-tableAddRowBefore {
+ background-image: url("themes/mediawiki/images/icons/table-insert-row-before.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-insert-row-before.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-insert-row-before.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/table-insert-row-before.png");
+}
+.oo-ui-icon-tableCaption {
+ background-image: url("themes/mediawiki/images/icons/table-caption.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-caption.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-caption.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/table-caption.png");
+}
+.oo-ui-icon-tableMergeCells {
+ background-image: url("themes/mediawiki/images/icons/table-merge-cells.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-merge-cells.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/table-merge-cells.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/table-merge-cells.png");
+}
+.oo-ui-icon-templateAdd {
+ background-image: url("themes/mediawiki/images/icons/templateAdd-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/templateAdd-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/templateAdd-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/templateAdd-ltr.png");
+}
+.oo-ui-icon-translation {
+ background-image: url("themes/mediawiki/images/icons/translation-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/translation-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/translation-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/translation-ltr.png");
+}
+.oo-ui-icon-wikiText {
+ background-image: url("themes/mediawiki/images/icons/wikiText.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/wikiText.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/wikiText.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/wikiText.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-core.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-core.css
new file mode 100644
index 00000000..7f3b236f
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-core.css
@@ -0,0 +1,88 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-edit {
+ background-image: url("themes/mediawiki/images/icons/edit-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/edit-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/edit-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/edit-ltr.png");
+}
+.oo-ui-icon-edit-progressive {
+ background-image: url("themes/mediawiki/images/icons/edit-ltr-progressive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/edit-ltr-progressive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/edit-ltr-progressive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/edit-ltr-progressive.png");
+}
+.oo-ui-icon-edit-invert {
+ background-image: url("themes/mediawiki/images/icons/edit-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/edit-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/edit-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/edit-ltr-invert.png");
+}
+.oo-ui-icon-editLock {
+ background-image: url("themes/mediawiki/images/icons/editLock-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/editLock-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/editLock-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/editLock-ltr.png");
+}
+.oo-ui-icon-editLock-invert {
+ background-image: url("themes/mediawiki/images/icons/editLock-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/editLock-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/editLock-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/editLock-ltr-invert.png");
+}
+.oo-ui-icon-editUndo {
+ background-image: url("themes/mediawiki/images/icons/editUndo-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/editUndo-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/editUndo-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/editUndo-ltr.png");
+}
+.oo-ui-icon-editUndo-invert {
+ background-image: url("themes/mediawiki/images/icons/editUndo-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/editUndo-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/editUndo-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/editUndo-ltr-invert.png");
+}
+.oo-ui-icon-link {
+ background-image: url("themes/mediawiki/images/icons/link-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/link-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/link-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/link-ltr.png");
+}
+.oo-ui-icon-link-invert {
+ background-image: url("themes/mediawiki/images/icons/link-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/link-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/link-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/link-ltr-invert.png");
+}
+.oo-ui-icon-linkExternal {
+ background-image: url("themes/mediawiki/images/icons/external-link-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/external-link-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/external-link-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/external-link-ltr.png");
+}
+.oo-ui-icon-linkExternal-invert {
+ background-image: url("themes/mediawiki/images/icons/external-link-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/external-link-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/external-link-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/external-link-ltr-invert.png");
+}
+.oo-ui-icon-linkSecure {
+ background-image: url("themes/mediawiki/images/icons/secure-link.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/secure-link.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/secure-link.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/secure-link.png");
+}
+.oo-ui-icon-linkSecure-invert {
+ background-image: url("themes/mediawiki/images/icons/secure-link-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/secure-link-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/secure-link-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/secure-link-invert.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-list.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-list.css
new file mode 100644
index 00000000..9708223a
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-list.css
@@ -0,0 +1,34 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-indent {
+ background-image: url("themes/mediawiki/images/icons/indent-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/indent-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/indent-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/indent-ltr.png");
+}
+.oo-ui-icon-listBullet {
+ background-image: url("themes/mediawiki/images/icons/listBullet-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/listBullet-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/listBullet-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/listBullet-ltr.png");
+}
+.oo-ui-icon-listNumbered {
+ background-image: url("themes/mediawiki/images/icons/listNumbered-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/listNumbered-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/listNumbered-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/listNumbered-ltr.png");
+}
+.oo-ui-icon-outdent {
+ background-image: url("themes/mediawiki/images/icons/outdent-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/outdent-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/outdent-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/outdent-ltr.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-styling.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-styling.css
new file mode 100644
index 00000000..ce739dcb
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-styling.css
@@ -0,0 +1,495 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-bigger {
+ background-image: url("themes/mediawiki/images/icons/bigger-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bigger-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bigger-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bigger-ltr.png");
+}
+.oo-ui-icon-smaller {
+ background-image: url("themes/mediawiki/images/icons/smaller-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/smaller-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/smaller-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/smaller-ltr.png");
+}
+.oo-ui-icon-subscript {
+ background-image: url("themes/mediawiki/images/icons/subscript-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/subscript-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/subscript-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/subscript-ltr.png");
+}
+.oo-ui-icon-superscript {
+ background-image: url("themes/mediawiki/images/icons/superscript-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/superscript-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/superscript-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/superscript-ltr.png");
+}
+.oo-ui-icon-bold {
+ background-image: url("themes/mediawiki/images/icons/bold-a.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-a.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-a.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-a.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(ar) {
+ background-image: url("themes/mediawiki/images/icons/bold-arab-ain.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-arab-ain.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-arab-ain.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-arab-ain.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(be) {
+ background-image: url("themes/mediawiki/images/icons/bold-cyrl-te.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-cyrl-te.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-cyrl-te.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-cyrl-te.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(cs) {
+ background-image: url("themes/mediawiki/images/icons/bold-b.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-b.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-b.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-b.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(en) {
+ background-image: url("themes/mediawiki/images/icons/bold-b.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-b.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-b.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-b.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(he) {
+ background-image: url("themes/mediawiki/images/icons/bold-b.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-b.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-b.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-b.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(ml) {
+ background-image: url("themes/mediawiki/images/icons/bold-b.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-b.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-b.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-b.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(pl) {
+ background-image: url("themes/mediawiki/images/icons/bold-b.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-b.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-b.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-b.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(da) {
+ background-image: url("themes/mediawiki/images/icons/bold-f.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-f.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(de) {
+ background-image: url("themes/mediawiki/images/icons/bold-f.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-f.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(hu) {
+ background-image: url("themes/mediawiki/images/icons/bold-f.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-f.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(ksh) {
+ background-image: url("themes/mediawiki/images/icons/bold-f.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-f.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(nn) {
+ background-image: url("themes/mediawiki/images/icons/bold-f.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-f.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(no) {
+ background-image: url("themes/mediawiki/images/icons/bold-f.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-f.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(sv) {
+ background-image: url("themes/mediawiki/images/icons/bold-f.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-f.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-f.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(es) {
+ background-image: url("themes/mediawiki/images/icons/bold-n.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-n.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-n.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-n.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(gl) {
+ background-image: url("themes/mediawiki/images/icons/bold-n.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-n.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-n.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-n.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(pt) {
+ background-image: url("themes/mediawiki/images/icons/bold-n.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-n.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-n.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-n.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(eu) {
+ background-image: url("themes/mediawiki/images/icons/bold-l.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-l.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-l.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-l.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(fi) {
+ background-image: url("themes/mediawiki/images/icons/bold-l.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-l.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-l.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-l.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(fa) {
+ background-image: url("themes/mediawiki/images/icons/bold-arab-dad.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-arab-dad.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-arab-dad.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-arab-dad.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(fr) {
+ background-image: url("themes/mediawiki/images/icons/bold-g.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-g.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-g.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-g.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(it) {
+ background-image: url("themes/mediawiki/images/icons/bold-g.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-g.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-g.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-g.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(hy) {
+ background-image: url("themes/mediawiki/images/icons/bold-armn-to.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-armn-to.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-armn-to.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-armn-to.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(ka) {
+ background-image: url("themes/mediawiki/images/icons/bold-geor-man.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-geor-man.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-geor-man.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-geor-man.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(ky) {
+ background-image: url("themes/mediawiki/images/icons/bold-cyrl-zhe.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-cyrl-zhe.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-cyrl-zhe.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-cyrl-zhe.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(ru) {
+ background-image: url("themes/mediawiki/images/icons/bold-cyrl-zhe.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-cyrl-zhe.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-cyrl-zhe.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-cyrl-zhe.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(nl) {
+ background-image: url("themes/mediawiki/images/icons/bold-v.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-v.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-v.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-v.png");
+}
+/* @noflip */
+.oo-ui-icon-bold:lang(os) {
+ background-image: url("themes/mediawiki/images/icons/bold-cyrl-be.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-cyrl-be.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bold-cyrl-be.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bold-cyrl-be.png");
+}
+.oo-ui-icon-italic {
+ background-image: url("themes/mediawiki/images/icons/italic-a.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-a.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-a.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-a.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(ar) {
+ background-image: url("themes/mediawiki/images/icons/italic-arab-meem.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-arab-meem.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-arab-meem.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-arab-meem.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(cs) {
+ background-image: url("themes/mediawiki/images/icons/italic-i.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-i.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(en) {
+ background-image: url("themes/mediawiki/images/icons/italic-i.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-i.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(fr) {
+ background-image: url("themes/mediawiki/images/icons/italic-i.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-i.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(he) {
+ background-image: url("themes/mediawiki/images/icons/italic-i.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-i.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(ml) {
+ background-image: url("themes/mediawiki/images/icons/italic-i.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-i.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(pl) {
+ background-image: url("themes/mediawiki/images/icons/italic-i.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-i.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(pt) {
+ background-image: url("themes/mediawiki/images/icons/italic-i.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-i.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-i.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(be) {
+ background-image: url("themes/mediawiki/images/icons/italic-k.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-k.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(da) {
+ background-image: url("themes/mediawiki/images/icons/italic-k.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-k.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(de) {
+ background-image: url("themes/mediawiki/images/icons/italic-k.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-k.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(fi) {
+ background-image: url("themes/mediawiki/images/icons/italic-k.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-k.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(ky) {
+ background-image: url("themes/mediawiki/images/icons/italic-k.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-k.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(nn) {
+ background-image: url("themes/mediawiki/images/icons/italic-k.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-k.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(no) {
+ background-image: url("themes/mediawiki/images/icons/italic-k.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-k.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(os) {
+ background-image: url("themes/mediawiki/images/icons/italic-k.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-k.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(sv) {
+ background-image: url("themes/mediawiki/images/icons/italic-k.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-k.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(ru) {
+ background-image: url("themes/mediawiki/images/icons/italic-k.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-k.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-k.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(es) {
+ background-image: url("themes/mediawiki/images/icons/italic-c.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-c.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-c.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-c.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(gl) {
+ background-image: url("themes/mediawiki/images/icons/italic-c.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-c.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-c.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-c.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(it) {
+ background-image: url("themes/mediawiki/images/icons/italic-c.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-c.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-c.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-c.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(nl) {
+ background-image: url("themes/mediawiki/images/icons/italic-c.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-c.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-c.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-c.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(eu) {
+ background-image: url("themes/mediawiki/images/icons/italic-e.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-e.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-e.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-e.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(fa) {
+ background-image: url("themes/mediawiki/images/icons/italic-arab-keheh-jeem.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-arab-keheh-jeem.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(hu) {
+ background-image: url("themes/mediawiki/images/icons/italic-d.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-d.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-d.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-d.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(hy) {
+ background-image: url("themes/mediawiki/images/icons/italic-armn-sha.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-armn-sha.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-armn-sha.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-armn-sha.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(ksh) {
+ background-image: url("themes/mediawiki/images/icons/italic-s.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-s.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-s.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-s.png");
+}
+/* @noflip */
+.oo-ui-icon-italic:lang(ka) {
+ background-image: url("themes/mediawiki/images/icons/italic-geor-kan.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-geor-kan.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/italic-geor-kan.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/italic-geor-kan.png");
+}
+.oo-ui-icon-strikethrough {
+ background-image: url("themes/mediawiki/images/icons/strikethrough-a.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/strikethrough-a.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/strikethrough-a.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/strikethrough-a.png");
+}
+/* @noflip */
+.oo-ui-icon-strikethrough:lang(en) {
+ background-image: url("themes/mediawiki/images/icons/strikethrough-s.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/strikethrough-s.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/strikethrough-s.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/strikethrough-s.png");
+}
+/* @noflip */
+.oo-ui-icon-strikethrough:lang(fi) {
+ background-image: url("themes/mediawiki/images/icons/strikethrough-y.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/strikethrough-y.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/strikethrough-y.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/strikethrough-y.png");
+}
+.oo-ui-icon-underline {
+ background-image: url("themes/mediawiki/images/icons/underline-a.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/underline-a.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/underline-a.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/underline-a.png");
+}
+/* @noflip */
+.oo-ui-icon-underline:lang(en) {
+ background-image: url("themes/mediawiki/images/icons/underline-u.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/underline-u.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/underline-u.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/underline-u.png");
+}
+.oo-ui-icon-textLanguage {
+ background-image: url("themes/mediawiki/images/icons/language.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/language.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/language.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/language.png");
+}
+.oo-ui-icon-textDirLTR {
+ background-image: url("themes/mediawiki/images/icons/text-dir-lefttoright.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/text-dir-lefttoright.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/text-dir-lefttoright.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/text-dir-lefttoright.png");
+}
+.oo-ui-icon-textDirRTL {
+ background-image: url("themes/mediawiki/images/icons/text-dir-righttoleft.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/text-dir-righttoleft.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/text-dir-righttoleft.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/text-dir-righttoleft.png");
+}
+.oo-ui-icon-textStyle {
+ background-image: url("themes/mediawiki/images/icons/text-style.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/text-style.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/text-style.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/text-style.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-interactions.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-interactions.css
new file mode 100644
index 00000000..23bad66d
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-interactions.css
@@ -0,0 +1,106 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-beta {
+ background-image: url("themes/mediawiki/images/icons/beta.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/beta.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/beta.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/beta.png");
+}
+.oo-ui-icon-betaLaunch {
+ background-image: url("themes/mediawiki/images/icons/betaLaunch.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/betaLaunch.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/betaLaunch.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/betaLaunch.png");
+}
+.oo-ui-icon-bookmark {
+ background-image: url("themes/mediawiki/images/icons/bookmark-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bookmark-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/bookmark-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/bookmark-ltr.png");
+}
+.oo-ui-icon-browser {
+ background-image: url("themes/mediawiki/images/icons/browser-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/browser-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/browser-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/browser-ltr.png");
+}
+.oo-ui-icon-clear {
+ background-image: url("themes/mediawiki/images/icons/clear.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/clear.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/clear.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/clear.png");
+}
+.oo-ui-icon-clock {
+ background-image: url("themes/mediawiki/images/icons/clock.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/clock.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/clock.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/clock.png");
+}
+.oo-ui-icon-funnel {
+ background-image: url("themes/mediawiki/images/icons/funnel-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/funnel-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/funnel-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/funnel-ltr.png");
+}
+.oo-ui-icon-heart {
+ background-image: url("themes/mediawiki/images/icons/heart.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/heart.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/heart.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/heart.png");
+}
+.oo-ui-icon-key {
+ background-image: url("themes/mediawiki/images/icons/key-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/key-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/key-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/key-ltr.png");
+}
+.oo-ui-icon-keyboard {
+ background-image: url("themes/mediawiki/images/icons/keyboard-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/keyboard-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/keyboard-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/keyboard-ltr.png");
+}
+.oo-ui-icon-logOut {
+ background-image: url("themes/mediawiki/images/icons/logOut-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/logOut-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/logOut-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/logOut-ltr.png");
+}
+.oo-ui-icon-newWindow {
+ background-image: url("themes/mediawiki/images/icons/newWindow-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/newWindow-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/newWindow-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/newWindow-ltr.png");
+}
+.oo-ui-icon-printer {
+ background-image: url("themes/mediawiki/images/icons/printer-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/printer-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/printer-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/printer-ltr.png");
+}
+.oo-ui-icon-ribbonPrize {
+ background-image: url("themes/mediawiki/images/icons/ribbonPrize.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/ribbonPrize.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/ribbonPrize.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/ribbonPrize.png");
+}
+.oo-ui-icon-sun {
+ background-image: url("themes/mediawiki/images/icons/sun-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/sun-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/sun-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/sun-ltr.png");
+}
+.oo-ui-icon-watchlist {
+ background-image: url("themes/mediawiki/images/icons/watchlist-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/watchlist-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/watchlist-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/watchlist-ltr.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-layout.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-layout.css
new file mode 100644
index 00000000..35ad9012
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-layout.css
@@ -0,0 +1,100 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-stripeFlow {
+ background-image: url("themes/mediawiki/images/icons/stripeFlow-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeFlow-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeFlow-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/stripeFlow-ltr.png");
+}
+.oo-ui-icon-stripeFlow-invert {
+ background-image: url("themes/mediawiki/images/icons/stripeFlow-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeFlow-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeFlow-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/stripeFlow-ltr-invert.png");
+}
+.oo-ui-icon-stripeSideMenu {
+ background-image: url("themes/mediawiki/images/icons/stripeSideMenu.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeSideMenu.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeSideMenu.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/stripeSideMenu.png");
+}
+.oo-ui-icon-stripeSideMenu-invert {
+ background-image: url("themes/mediawiki/images/icons/stripeSideMenu-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeSideMenu-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeSideMenu-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/stripeSideMenu-invert.png");
+}
+.oo-ui-icon-stripeSummary {
+ background-image: url("themes/mediawiki/images/icons/stripeSummary-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeSummary-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeSummary-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/stripeSummary-ltr.png");
+}
+.oo-ui-icon-stripeSummary-invert {
+ background-image: url("themes/mediawiki/images/icons/stripeSummary-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeSummary-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeSummary-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/stripeSummary-ltr-invert.png");
+}
+.oo-ui-icon-stripeToC {
+ background-image: url("themes/mediawiki/images/icons/stripeToC-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeToC-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeToC-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/stripeToC-ltr.png");
+}
+.oo-ui-icon-stripeToC-progressive {
+ background-image: url("themes/mediawiki/images/icons/stripeToC-ltr-progressive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeToC-ltr-progressive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeToC-ltr-progressive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/stripeToC-ltr-progressive.png");
+}
+.oo-ui-icon-stripeToC-invert {
+ background-image: url("themes/mediawiki/images/icons/stripeToC-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeToC-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stripeToC-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/stripeToC-ltr-invert.png");
+}
+.oo-ui-icon-viewCompact {
+ background-image: url("themes/mediawiki/images/icons/viewCompact.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/viewCompact.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/viewCompact.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/viewCompact.png");
+}
+.oo-ui-icon-viewCompact-invert {
+ background-image: url("themes/mediawiki/images/icons/viewCompact-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/viewCompact-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/viewCompact-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/viewCompact-invert.png");
+}
+.oo-ui-icon-viewDetails {
+ background-image: url("themes/mediawiki/images/icons/viewDetails-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/viewDetails-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/viewDetails-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/viewDetails-ltr.png");
+}
+.oo-ui-icon-viewDetails-invert {
+ background-image: url("themes/mediawiki/images/icons/viewDetails-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/viewDetails-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/viewDetails-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/viewDetails-ltr-invert.png");
+}
+.oo-ui-icon-visionSimulator {
+ background-image: url("themes/mediawiki/images/icons/visionSimulator.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/visionSimulator.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/visionSimulator.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/visionSimulator.png");
+}
+.oo-ui-icon-visionSimulator-invert {
+ background-image: url("themes/mediawiki/images/icons/visionSimulator-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/visionSimulator-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/visionSimulator-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/visionSimulator-invert.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-location.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-location.css
new file mode 100644
index 00000000..d7dad243
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-location.css
@@ -0,0 +1,34 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-map {
+ background-image: url("themes/mediawiki/images/icons/map-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/map-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/map-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/map-ltr.png");
+}
+.oo-ui-icon-mapPin {
+ background-image: url("themes/mediawiki/images/icons/mapPin.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/mapPin.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/mapPin.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/mapPin.png");
+}
+.oo-ui-icon-mapPinAdd {
+ background-image: url("themes/mediawiki/images/icons/mapPinAdd-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/mapPinAdd-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/mapPinAdd-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/mapPinAdd-ltr.png");
+}
+.oo-ui-icon-wikitrail {
+ background-image: url("themes/mediawiki/images/icons/wikitrail-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/wikitrail-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/wikitrail-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/wikitrail-ltr.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-media.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-media.css
new file mode 100644
index 00000000..650cfa2f
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-media.css
@@ -0,0 +1,46 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-image {
+ background-image: url("themes/mediawiki/images/icons/image-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/image-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/image-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/image-ltr.png");
+}
+.oo-ui-icon-imageAdd {
+ background-image: url("themes/mediawiki/images/icons/imageAdd-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/imageAdd-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/imageAdd-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/imageAdd-ltr.png");
+}
+.oo-ui-icon-imageLock {
+ background-image: url("themes/mediawiki/images/icons/imageLock-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/imageLock-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/imageLock-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/imageLock-ltr.png");
+}
+.oo-ui-icon-photoGallery {
+ background-image: url("themes/mediawiki/images/icons/photoGallery-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/photoGallery-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/photoGallery-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/photoGallery-ltr.png");
+}
+.oo-ui-icon-play {
+ background-image: url("themes/mediawiki/images/icons/play-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/play-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/play-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/play-ltr.png");
+}
+.oo-ui-icon-stop {
+ background-image: url("themes/mediawiki/images/icons/stop.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stop.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/stop.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/stop.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-moderation.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-moderation.css
new file mode 100644
index 00000000..97eb0d52
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-moderation.css
@@ -0,0 +1,148 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-block {
+ background-image: url("themes/mediawiki/images/icons/block.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/block.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/block.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/block.png");
+}
+.oo-ui-icon-block-destructive {
+ background-image: url("themes/mediawiki/images/icons/block-destructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/block-destructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/block-destructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/block-destructive.png");
+}
+.oo-ui-icon-block-invert {
+ background-image: url("themes/mediawiki/images/icons/block-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/block-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/block-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/block-invert.png");
+}
+.oo-ui-icon-blockUndo {
+ background-image: url("themes/mediawiki/images/icons/blockUndo-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/blockUndo-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/blockUndo-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/blockUndo-ltr.png");
+}
+.oo-ui-icon-blockUndo-invert {
+ background-image: url("themes/mediawiki/images/icons/blockUndo-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/blockUndo-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/blockUndo-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/blockUndo-ltr-invert.png");
+}
+.oo-ui-icon-flag {
+ background-image: url("themes/mediawiki/images/icons/flag-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/flag-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/flag-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/flag-ltr.png");
+}
+.oo-ui-icon-flag-invert {
+ background-image: url("themes/mediawiki/images/icons/flag-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/flag-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/flag-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/flag-ltr-invert.png");
+}
+.oo-ui-icon-flagUndo {
+ background-image: url("themes/mediawiki/images/icons/flagUndo-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/flagUndo-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/flagUndo-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/flagUndo-ltr.png");
+}
+.oo-ui-icon-flagUndo-invert {
+ background-image: url("themes/mediawiki/images/icons/flagUndo-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/flagUndo-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/flagUndo-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/flagUndo-ltr-invert.png");
+}
+.oo-ui-icon-lock {
+ background-image: url("themes/mediawiki/images/icons/lock-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/lock-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/lock-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/lock-ltr.png");
+}
+.oo-ui-icon-lock-destructive {
+ background-image: url("themes/mediawiki/images/icons/lock-ltr-destructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/lock-ltr-destructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/lock-ltr-destructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/lock-ltr-destructive.png");
+}
+.oo-ui-icon-lock-invert {
+ background-image: url("themes/mediawiki/images/icons/lock-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/lock-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/lock-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/lock-ltr-invert.png");
+}
+.oo-ui-icon-star {
+ background-image: url("themes/mediawiki/images/icons/star.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/star.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/star.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/star.png");
+}
+.oo-ui-icon-star-invert {
+ background-image: url("themes/mediawiki/images/icons/star-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/star-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/star-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/star-invert.png");
+}
+.oo-ui-icon-trash {
+ background-image: url("themes/mediawiki/images/icons/trash.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/trash.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/trash.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/trash.png");
+}
+.oo-ui-icon-trash-invert {
+ background-image: url("themes/mediawiki/images/icons/trash-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/trash-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/trash-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/trash-invert.png");
+}
+.oo-ui-icon-trashUndo {
+ background-image: url("themes/mediawiki/images/icons/trashUndo-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/trashUndo-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/trashUndo-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/trashUndo-ltr.png");
+}
+.oo-ui-icon-trashUndo-invert {
+ background-image: url("themes/mediawiki/images/icons/trashUndo-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/trashUndo-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/trashUndo-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/trashUndo-ltr-invert.png");
+}
+.oo-ui-icon-unLock {
+ background-image: url("themes/mediawiki/images/icons/unLock-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/unLock-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/unLock-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/unLock-ltr.png");
+}
+.oo-ui-icon-unLock-destructive {
+ background-image: url("themes/mediawiki/images/icons/unLock-ltr-destructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/unLock-ltr-destructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/unLock-ltr-destructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/unLock-ltr-destructive.png");
+}
+.oo-ui-icon-unLock-invert {
+ background-image: url("themes/mediawiki/images/icons/unLock-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/unLock-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/unLock-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/unLock-ltr-invert.png");
+}
+.oo-ui-icon-unStar {
+ background-image: url("themes/mediawiki/images/icons/unStar.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/unStar.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/unStar.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/unStar.png");
+}
+.oo-ui-icon-unStar-invert {
+ background-image: url("themes/mediawiki/images/icons/unStar-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/unStar-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/unStar-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/unStar-invert.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-movement.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-movement.css
new file mode 100644
index 00000000..148b54e5
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-movement.css
@@ -0,0 +1,64 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-arrowNext {
+ background-image: url("themes/mediawiki/images/icons/arrow-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arrow-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arrow-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/arrow-ltr.png");
+}
+.oo-ui-icon-arrowLast {
+ background-image: url("themes/mediawiki/images/icons/arrow-rtl.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arrow-rtl.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arrow-rtl.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/arrow-rtl.png");
+}
+.oo-ui-icon-caretNext {
+ background-image: url("themes/mediawiki/images/icons/caret-rtl.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/caret-rtl.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/caret-rtl.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/caret-rtl.png");
+}
+.oo-ui-icon-caretLast {
+ background-image: url("themes/mediawiki/images/icons/caret-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/caret-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/caret-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/caret-ltr.png");
+}
+.oo-ui-icon-caretDown {
+ background-image: url("themes/mediawiki/images/icons/caretDown.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/caretDown.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/caretDown.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/caretDown.png");
+}
+.oo-ui-icon-caretUp {
+ background-image: url("themes/mediawiki/images/icons/caretUp.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/caretUp.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/caretUp.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/caretUp.png");
+}
+.oo-ui-icon-downTriangle {
+ background-image: url("themes/mediawiki/images/icons/downTriangle.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/downTriangle.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/downTriangle.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/downTriangle.png");
+}
+.oo-ui-icon-move {
+ background-image: url("themes/mediawiki/images/icons/move.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/move.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/move.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/move.png");
+}
+.oo-ui-icon-upTriangle {
+ background-image: url("themes/mediawiki/images/icons/upTriangle.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/upTriangle.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/upTriangle.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/upTriangle.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-user.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-user.css
new file mode 100644
index 00000000..9eabc174
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-user.css
@@ -0,0 +1,34 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-userActive {
+ background-image: url("themes/mediawiki/images/icons/userActive-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/userActive-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/userActive-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/userActive-ltr.png");
+}
+.oo-ui-icon-userAvatar {
+ background-image: url("themes/mediawiki/images/icons/userAvatar.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/userAvatar.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/userAvatar.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/userAvatar.png");
+}
+.oo-ui-icon-userInactive {
+ background-image: url("themes/mediawiki/images/icons/userInactive-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/userInactive-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/userInactive-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/userInactive-ltr.png");
+}
+.oo-ui-icon-userTalk {
+ background-image: url("themes/mediawiki/images/icons/userTalk-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/userTalk-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/userTalk-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/userTalk-ltr.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-wikimedia.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-wikimedia.css
new file mode 100644
index 00000000..0c905d08
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-wikimedia.css
@@ -0,0 +1,28 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+.oo-ui-icon-logoCC {
+ background-image: url("themes/mediawiki/images/icons/logo-cc.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/logo-cc.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/logo-cc.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/logo-cc.png");
+}
+.oo-ui-icon-logoWikimediaCommons {
+ background-image: url("themes/mediawiki/images/icons/logo-wikimediaCommons.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/logo-wikimediaCommons.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/logo-wikimediaCommons.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/logo-wikimediaCommons.png");
+}
+.oo-ui-icon-logoWikipedia {
+ background-image: url("themes/mediawiki/images/icons/logo-wikipedia.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/logo-wikipedia.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/logo-wikipedia.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/logo-wikipedia.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-noimages.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-noimages.css
new file mode 100644
index 00000000..12e80c11
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-noimages.css
@@ -0,0 +1,2660 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+@-webkit-keyframes oo-ui-progressBarWidget-slide {
+ from {
+ margin-left: -40%;
+ }
+ to {
+ margin-left: 100%;
+ }
+}
+@-moz-keyframes oo-ui-progressBarWidget-slide {
+ from {
+ margin-left: -40%;
+ }
+ to {
+ margin-left: 100%;
+ }
+}
+@-ms-keyframes oo-ui-progressBarWidget-slide {
+ from {
+ margin-left: -40%;
+ }
+ to {
+ margin-left: 100%;
+ }
+}
+@-o-keyframes oo-ui-progressBarWidget-slide {
+ from {
+ margin-left: -40%;
+ }
+ to {
+ margin-left: 100%;
+ }
+}
+@keyframes oo-ui-progressBarWidget-slide {
+ from {
+ margin-left: -40%;
+ }
+ to {
+ margin-left: 100%;
+ }
+}
+/* @noflip */
+.oo-ui-rtl {
+ direction: rtl;
+}
+/* @noflip */
+.oo-ui-ltr {
+ direction: ltr;
+}
+.oo-ui-element-hidden {
+ display: none !important;
+}
+.oo-ui-buttonElement > .oo-ui-buttonElement-button {
+ cursor: pointer;
+ display: inline-block;
+ vertical-align: middle;
+ font: inherit;
+ white-space: nowrap;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon,
+.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ display: none;
+}
+.oo-ui-buttonElement.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
+ cursor: default;
+}
+.oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
+.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ display: inline-block;
+ vertical-align: middle;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-buttonElement-frameless {
+ display: inline-block;
+ position: relative;
+}
+.oo-ui-buttonElement-frameless.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
+ display: inline-block;
+ vertical-align: top;
+ text-align: center;
+}
+.oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ cursor: default;
+}
+.oo-ui-buttonElement > .oo-ui-buttonElement-button {
+ font-weight: bold;
+}
+.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ margin-left: 0;
+}
+.oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ width: 0.9375em;
+ height: 0.9375em;
+ margin: 0.46875em;
+}
+.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ margin-left: 0.46875em;
+}
+.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ width: 1.875em;
+ height: 1.875em;
+}
+.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.2);
+ outline: none;
+}
+.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button .oo-ui-indicatorElement-indicator {
+ margin-right: 0;
+}
+.oo-ui-buttonElement-frameless.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ margin-left: 0.25em;
+ margin-right: 0.25em;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #555555;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #444444;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
+ color: #347bff;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #777777;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #1f4999;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
+ color: #00af89;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #777777;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #005946;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
+ color: #d11d13;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #777777;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #73100a;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
+ color: #cccccc;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon,
+.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
+ margin: 0.1em 0;
+ padding: 0.2em 0.8em;
+ border-radius: 2px;
+ -webkit-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+ -moz-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+ -ms-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+ -o-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+ transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+}
+.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button:focus {
+ outline: none;
+}
+.oo-ui-buttonElement-framed > input.oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ line-height: 1.875em;
+}
+.oo-ui-buttonElement-framed.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ margin-left: -0.5em;
+ margin-right: -0.5em;
+}
+.oo-ui-buttonElement-framed.oo-ui-iconElement.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ margin-right: 0.3em;
+}
+.oo-ui-buttonElement-framed.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ /* -0.5 - 0.475 */
+ margin-left: -0.005em;
+ margin-right: -0.005em;
+}
+.oo-ui-buttonElement-framed.oo-ui-indicatorElement.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
+.oo-ui-buttonElement-framed.oo-ui-indicatorElement.oo-ui-iconElement:not( .oo-ui-labelElement ) > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ margin-left: 0.46875em;
+ margin-right: -0.275em;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background: #dddddd;
+ border: 1px solid #dddddd;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
+ color: #555555;
+ background-color: #ffffff;
+ border: 1px solid #cdcdcd;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button:hover {
+ background-color: #ebebeb;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ background-color: #d9d9d9;
+ border-color: #d9d9d9;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
+ color: #347bff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover {
+ background-color: rgba(52, 123, 255, 0.1);
+ border-color: rgba(31, 73, 153, 0.5);
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #1f4999;
+ border-color: #1f4999;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #1f4999;
+ border-color: #1f4999;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
+ color: #00af89;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover {
+ background-color: rgba(0, 171, 137, 0.1);
+ border-color: rgba(0, 89, 70, 0.5);
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #005946;
+ border-color: #005946;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #005946;
+ border-color: #005946;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
+ color: #d11d13;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover {
+ background-color: rgba(209, 29, 19, 0.1);
+ border-color: rgba(115, 16, 10, 0.5);
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #73100a;
+ border-color: #73100a;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #73100a;
+ border-color: #73100a;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #347bff;
+ border-color: #347bff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover {
+ background: #2962cc;
+ border-color: #2962cc;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #ffffff;
+ border-color: #347bff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #1f4999;
+ border-color: #1f4999;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #00af89;
+ border-color: #00af89;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover {
+ background: #008064;
+ border-color: #008064;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #ffffff;
+ border-color: #00af89;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #005946;
+ border-color: #005946;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #d11d13;
+ border-color: #d11d13;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover {
+ background: #8c130d;
+ border-color: #8c130d;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #ffffff;
+ border-color: #d11d13;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #73100a;
+ border-color: #73100a;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-clippableElement-clippable {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-draggableElement {
+ cursor: -webkit-grab -moz-grab, url(images/grab.cur), move;
+ /*
+ * HACK: In order to style horizontally, we must override
+ * OO.ui.OptionWidget's display rule that is currently set
+ * to be 'block'
+ */
+}
+.oo-ui-draggableElement-dragging {
+ cursor: -webkit-grabbing -moz-grabbing, url(images/grabbing.cur), move;
+ background: rgba(0, 0, 0, 0.2);
+ opacity: 0.4;
+}
+.oo-ui-draggableGroupElement-horizontal .oo-ui-draggableElement.oo-ui-optionWidget {
+ display: inline-block;
+}
+.oo-ui-draggableGroupElement-placeholder {
+ position: absolute;
+ display: block;
+ background: rgba(0, 0, 0, 0.4);
+}
+.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-iconElement.oo-ui-iconElement-icon {
+ background-size: contain;
+ background-position: center center;
+}
+.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator,
+.oo-ui-indicatorElement.oo-ui-indicatorElement-indicator {
+ background-size: contain;
+ background-position: center center;
+}
+.oo-ui-lookupElement > .oo-ui-menuSelectWidget {
+ z-index: 1;
+ width: 100%;
+}
+.oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous > .oo-ui-panelLayout-scrollable {
+ overflow-y: hidden;
+}
+.oo-ui-bookletLayout-stackLayout > .oo-ui-panelLayout {
+ 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-editable > .oo-ui-outlineSelectWidget {
+ 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;
+}
+.oo-ui-bookletLayout-stackLayout > .oo-ui-panelLayout {
+ padding: 1.5em;
+}
+.oo-ui-bookletLayout-outlinePanel {
+ border-right: 1px solid #dddddd;
+}
+.oo-ui-bookletLayout-outlinePanel > .oo-ui-outlineControlsWidget {
+ box-shadow: 0 0 0.25em rgba(0, 0, 0, 0.25);
+}
+.oo-ui-indexLayout > .oo-ui-menuLayout-menu {
+ height: 3em;
+}
+.oo-ui-indexLayout > .oo-ui-menuLayout-content {
+ top: 3em;
+}
+.oo-ui-indexLayout-stackLayout > .oo-ui-panelLayout {
+ padding: 1.5em;
+}
+.oo-ui-fieldLayout {
+ display: block;
+ margin-bottom: 1em;
+}
+.oo-ui-fieldLayout:before,
+.oo-ui-fieldLayout:after {
+ content: " ";
+ display: table;
+}
+.oo-ui-fieldLayout:after {
+ clear: both;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+ display: block;
+ float: left;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ text-align: right;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body {
+ display: table;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+ display: table-cell;
+ vertical-align: middle;
+}
+.oo-ui-fieldLayout.oo-ui-labelElement.oo-ui-fieldLayout-align-top > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ display: inline-block;
+}
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help {
+ float: right;
+}
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+ z-index: 1;
+}
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help .oo-ui-fieldLayout-help-content {
+ padding: 0.5em 0.75em;
+ line-height: 1.5em;
+}
+.oo-ui-fieldLayout:last-child {
+ margin-bottom: 0;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ padding-top: 0.5em;
+ margin-right: 5%;
+ width: 35%;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+ width: 60%;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ padding: 0.5em;
+ padding-left: 1em;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+ padding: 0.5em 0;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ padding: 0.5em 0;
+}
+.oo-ui-fieldLayout > .oo-ui-popupButtonWidget {
+ margin-right: 0;
+ margin-top: 0.25em;
+}
+.oo-ui-fieldLayout > .oo-ui-popupButtonWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-fieldLayout-disabled .oo-ui-labelElement-label {
+ color: #cccccc;
+}
+.oo-ui-actionFieldLayout-field {
+ display: table;
+ table-layout: fixed;
+ width: 100%;
+}
+.oo-ui-actionFieldLayout-input,
+.oo-ui-actionFieldLayout-button {
+ display: table-cell;
+ vertical-align: middle;
+}
+.oo-ui-actionFieldLayout-input {
+ padding-right: 1em;
+}
+.oo-ui-actionFieldLayout-button {
+ width: 1%;
+ white-space: nowrap;
+}
+.oo-ui-fieldsetLayout {
+ position: relative;
+ margin: 0;
+ padding: 0;
+ border: none;
+}
+.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
+ display: block;
+ position: absolute;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-fieldsetLayout.oo-ui-labelElement > .oo-ui-labelElement-label {
+ display: inline-block;
+}
+.oo-ui-fieldsetLayout > .oo-ui-fieldsetLayout-help {
+ float: right;
+}
+.oo-ui-fieldsetLayout > .oo-ui-fieldsetLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+ z-index: 1;
+}
+.oo-ui-fieldsetLayout > .oo-ui-fieldsetLayout-help .oo-ui-fieldsetLayout-help-content {
+ padding: 0.5em 0.75em;
+ line-height: 1.5em;
+}
+.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout,
+.oo-ui-fieldsetLayout + .oo-ui-formLayout {
+ margin-top: 2em;
+}
+.oo-ui-fieldsetLayout > .oo-ui-labelElement-label {
+ font-size: 1.1em;
+ margin-bottom: 0.5em;
+ padding: 0.25em 0;
+ font-weight: bold;
+}
+.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-labelElement-label {
+ padding-left: 2em;
+ line-height: 1.8em;
+}
+.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
+ left: 0;
+ top: 0.25em;
+ width: 1.875em;
+ height: 1.875em;
+}
+.oo-ui-fieldsetLayout > .oo-ui-popupButtonWidget {
+ margin-right: 0;
+}
+.oo-ui-fieldsetLayout > .oo-ui-popupButtonWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-formLayout + .oo-ui-fieldsetLayout,
+.oo-ui-formLayout + .oo-ui-formLayout {
+ margin-top: 2em;
+}
+.oo-ui-menuLayout {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+.oo-ui-menuLayout-menu,
+.oo-ui-menuLayout-content {
+ position: absolute;
+ -webkit-transition: all ease-in-out 200ms;
+ -moz-transition: all ease-in-out 200ms;
+ -ms-transition: all ease-in-out 200ms;
+ -o-transition: all ease-in-out 200ms;
+ transition: all ease-in-out 200ms;
+}
+.oo-ui-menuLayout-menu {
+ height: 18em;
+ width: 18em;
+}
+.oo-ui-menuLayout-content {
+ top: 18em;
+ left: 18em;
+ right: 18em;
+ bottom: 18em;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-hideMenu .oo-ui-menuLayout-menu {
+ width: 0 !important;
+ height: 0 !important;
+ overflow: hidden;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-hideMenu .oo-ui-menuLayout-content {
+ top: 0 !important;
+ left: 0 !important;
+ right: 0 !important;
+ bottom: 0 !important;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-top .oo-ui-menuLayout-menu {
+ width: auto !important;
+ left: 0;
+ top: 0;
+ right: 0;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-top .oo-ui-menuLayout-content {
+ right: 0 !important;
+ bottom: 0 !important;
+ left: 0 !important;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-after .oo-ui-menuLayout-menu {
+ height: auto !important;
+ top: 0;
+ right: 0;
+ bottom: 0;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-after .oo-ui-menuLayout-content {
+ bottom: 0 !important;
+ left: 0 !important;
+ top: 0 !important;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-bottom .oo-ui-menuLayout-menu {
+ width: auto !important;
+ right: 0;
+ bottom: 0;
+ left: 0;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-bottom .oo-ui-menuLayout-content {
+ left: 0 !important;
+ top: 0 !important;
+ right: 0 !important;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-before .oo-ui-menuLayout-menu {
+ height: auto !important;
+ bottom: 0;
+ left: 0;
+ top: 0;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-before .oo-ui-menuLayout-content {
+ top: 0 !important;
+ right: 0 !important;
+ bottom: 0 !important;
+}
+.oo-ui-panelLayout {
+ position: relative;
+}
+.oo-ui-panelLayout-scrollable {
+ overflow-y: auto;
+}
+.oo-ui-panelLayout-expanded {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+.oo-ui-panelLayout-padded {
+ padding: 1.25em;
+}
+.oo-ui-panelLayout-framed {
+ border: 1px solid #aaaaaa;
+ border-radius: 0.2em;
+ box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2);
+}
+.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
+ display: block;
+ position: relative;
+}
+.oo-ui-popupTool .oo-ui-popupWidget-popup,
+.oo-ui-popupTool .oo-ui-popupWidget-anchor {
+ z-index: 4;
+}
+.oo-ui-popupTool .oo-ui-popupWidget {
+ /* @noflip */
+ margin-left: 1.25em;
+}
+.oo-ui-toolGroupTool > .oo-ui-popupToolGroup {
+ border: 0;
+ border-radius: 0;
+ margin: 0;
+}
+.oo-ui-toolGroupTool > .oo-ui-toolGroup {
+ border-right: none;
+}
+.oo-ui-toolGroupTool > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle {
+ height: 2.5em;
+ padding: 0.3125em;
+}
+.oo-ui-toolGroupTool > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
+ height: 2.5em;
+ width: 1.875em;
+}
+.oo-ui-toolGroupTool > .oo-ui-popupToolGroup.oo-ui-labelElement > .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ line-height: 2.1em;
+}
+.oo-ui-toolGroup {
+ display: inline-block;
+ vertical-align: middle;
+ border-radius: 0;
+ border-right: 1px solid #dddddd;
+}
+.oo-ui-toolGroup-empty {
+ display: none;
+}
+.oo-ui-toolGroup .oo-ui-tool-link {
+ text-decoration: none;
+}
+.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-toolbar-narrow .oo-ui-toolGroup + .oo-ui-toolGroup {
+ margin-left: 0;
+}
+.oo-ui-toolGroup .oo-ui-toolGroup .oo-ui-widget-enabled {
+ border-right: none !important;
+}
+.oo-ui-barToolGroup > .oo-ui-iconElement-icon,
+.oo-ui-barToolGroup > .oo-ui-labelElement-label {
+ display: none;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
+ cursor: pointer;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool {
+ display: inline-block;
+ position: relative;
+ vertical-align: top;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
+ display: block;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-tool-accel {
+ display: none;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-iconElement > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ display: inline-block;
+ vertical-align: top;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-iconElement > .oo-ui-tool-link .oo-ui-tool-title {
+ display: none;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-iconElement.oo-ui-tool-with-label > .oo-ui-tool-link .oo-ui-tool-title {
+ display: inline;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link {
+ cursor: default;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
+ height: 1.875em;
+ padding: 0.625em;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ height: 1.875em;
+ width: 1.875em;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-tool-title {
+ line-height: 2.1em;
+ padding: 0 0.4em;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:hover {
+ border-color: rgba(0, 0, 0, 0.2);
+ background-color: #eeeeee;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-tool-title {
+ color: #555555;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled {
+ border-color: rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+ background-color: #e5e5e5;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled:hover {
+ background-color: #eeeeee;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
+ border-left-color: rgba(0, 0, 0, 0.1);
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-tool-title {
+ color: #cccccc;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.7;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:hover > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.9;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:active {
+ background-color: #e7e7e7;
+}
+.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-tool-title {
+ color: #cccccc;
+}
+.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-popupToolGroup {
+ position: relative;
+ height: 3.125em;
+ min-width: 2em;
+}
+.oo-ui-popupToolGroup-handle {
+ display: block;
+ cursor: pointer;
+}
+.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator,
+.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
+ position: absolute;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-popupToolGroup.oo-ui-widget-disabled .oo-ui-popupToolGroup-handle {
+ cursor: default;
+}
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
+ display: none;
+ position: absolute;
+ z-index: 4;
+}
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconElement-icon {
+ background-repeat: no-repeat;
+ background-position: center center;
+}
+.oo-ui-popupToolGroup-active.oo-ui-widget-enabled > .oo-ui-toolGroup-tools {
+ display: block;
+}
+.oo-ui-popupToolGroup-left > .oo-ui-toolGroup-tools {
+ left: 0;
+}
+.oo-ui-popupToolGroup-right > .oo-ui-toolGroup-tools {
+ right: 0;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link {
+ display: table;
+ width: 100%;
+ vertical-align: middle;
+ white-space: nowrap;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon,
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel,
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+ display: table-cell;
+ vertical-align: middle;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel {
+ text-align: right;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel:not(:empty) {
+ padding-left: 3em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup {
+ min-width: 1.875em;
+}
+.oo-ui-popupToolGroup.oo-ui-iconElement {
+ min-width: 3.125em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-iconElement {
+ min-width: 2.5em;
+}
+.oo-ui-popupToolGroup.oo-ui-indicatorElement.oo-ui-iconElement {
+ min-width: 4.375em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-indicatorElement.oo-ui-iconElement {
+ min-width: 3.75em;
+}
+.oo-ui-popupToolGroup.oo-ui-labelElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ line-height: 2.6em;
+ margin: 0 1em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-labelElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ margin: 0 0.5em;
+}
+.oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-iconElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ margin-left: 3em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-iconElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ margin-left: 2.5em;
+}
+.oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ margin-right: 2em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ margin-right: 1.75em;
+}
+.oo-ui-popupToolGroup.oo-ui-widget-enabled .oo-ui-popupToolGroup-handle:hover {
+ background-color: #eeeeee;
+}
+.oo-ui-popupToolGroup.oo-ui-widget-enabled .oo-ui-popupToolGroup-handle:active {
+ background-color: #e5e5e5;
+}
+.oo-ui-popupToolGroup-handle {
+ padding: 0.3125em;
+ height: 2.5em;
+}
+.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
+ width: 0.9375em;
+ height: 1.625em;
+ margin: 0.78125em 0.5em;
+ top: 0;
+ right: 0;
+ opacity: 0.3;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
+ right: -0.3125em;
+}
+.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
+ width: 1.875em;
+ height: 2.6em;
+ margin: 0.25em;
+ top: 0;
+ left: 0.3125em;
+ opacity: 0.7;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
+ left: 0;
+}
+.oo-ui-popupToolGroup-header {
+ line-height: 2.6em;
+ margin: 0 0.6em;
+ font-weight: bold;
+}
+.oo-ui-popupToolGroup-active.oo-ui-widget-enabled {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+ background-color: #eeeeee;
+}
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
+ top: 3.125em;
+ margin: 0 -1px;
+ border: 1px solid #cccccc;
+ background-color: #ffffff;
+ box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
+ min-width: 16em;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link {
+ padding: 0.4em 0.625em;
+ box-sizing: border-box;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
+ height: 2.5em;
+ width: 1.875em;
+ min-width: 1.875em;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+ padding-left: 0.5em;
+ color: #000000;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel,
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+ line-height: 2em;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel {
+ color: #888888;
+}
+.oo-ui-listToolGroup .oo-ui-tool {
+ display: block;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-listToolGroup .oo-ui-tool-link {
+ cursor: pointer;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+ cursor: default;
+}
+.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
+ border-color: rgba(0, 0, 0, 0.2);
+ background-color: #eeeeee;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:active {
+ background-color: #e7e7e7;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.9;
+}
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled {
+ border-color: rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+ background-color: #e5e5e5;
+}
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
+ border-top-color: rgba(0, 0, 0, 0.1);
+}
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled:hover {
+ border-color: rgba(0, 0, 0, 0.2);
+ background-color: #eeeeee;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
+ color: #cccccc;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-accel {
+ color: #dddddd;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-listToolGroup.oo-ui-widget-disabled {
+ color: #cccccc;
+}
+.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
+.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-menuToolGroup .oo-ui-tool {
+ display: block;
+}
+.oo-ui-menuToolGroup .oo-ui-tool-link {
+ cursor: pointer;
+}
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+ cursor: default;
+}
+.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
+ min-width: 10em;
+}
+.oo-ui-toolbar-narrow .oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
+ min-width: 8.125em;
+}
+.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
+ background-image: none;
+}
+.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconElement-icon {
+ background-image: url("themes/mediawiki/images/icons/check.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check.png");
+}
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
+ background-color: #eeeeee;
+}
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
+ color: #cccccc;
+}
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-menuToolGroup.oo-ui-widget-disabled {
+ color: #cccccc;
+}
+.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
+.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-toolbar {
+ clear: both;
+}
+.oo-ui-toolbar-bar {
+ line-height: 1em;
+ position: relative;
+}
+.oo-ui-toolbar-actions {
+ float: right;
+}
+.oo-ui-toolbar-actions .oo-ui-toolbar {
+ display: inline-block;
+}
+.oo-ui-toolbar-tools {
+ display: inline;
+ white-space: nowrap;
+}
+.oo-ui-toolbar-narrow .oo-ui-toolbar-tools {
+ white-space: normal;
+}
+.oo-ui-toolbar-tools .oo-ui-tool {
+ white-space: normal;
+}
+.oo-ui-toolbar-tools,
+.oo-ui-toolbar-actions,
+.oo-ui-toolbar-shadow {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-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 {
+ background-position: left top;
+ background-repeat: repeat-x;
+ position: absolute;
+ width: 100%;
+ pointer-events: none;
+}
+.oo-ui-toolbar-bar {
+ border-bottom: 1px solid #cccccc;
+ background-color: #ffffff;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ font-weight: 500;
+ color: #555555;
+}
+.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
+ border: none;
+ background: none;
+ box-shadow: none;
+}
+.oo-ui-toolbar-actions > .oo-ui-buttonElement {
+ margin-top: 0.25em;
+ margin-bottom: 0.25em;
+}
+.oo-ui-toolbar-actions > .oo-ui-toolbar,
+.oo-ui-toolbar-actions > .oo-ui-buttonElement:last-child {
+ margin-right: 0.5em;
+}
+.oo-ui-optionWidget {
+ position: relative;
+ display: block;
+ cursor: pointer;
+ padding: 0.25em 0.5em;
+ border: none;
+}
+.oo-ui-optionWidget.oo-ui-widget-disabled {
+ cursor: default;
+}
+.oo-ui-optionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ display: block;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+.oo-ui-optionWidget-highlighted {
+ background-color: #eeeeee;
+}
+.oo-ui-optionWidget .oo-ui-labelElement-label {
+ line-height: 1.5em;
+}
+.oo-ui-selectWidget-depressed .oo-ui-optionWidget-selected,
+.oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed,
+.oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed.oo-ui-optionWidget-highlighted,
+.oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed.oo-ui-optionWidget-highlighted.oo-ui-optionWidget-selected {
+ background-color: #d0d0d0;
+}
+.oo-ui-optionWidget.oo-ui-widget-disabled {
+ color: #cccccc;
+}
+.oo-ui-decoratedOptionWidget {
+ padding: 0.5em 2em 0.5em 3em;
+}
+.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon,
+.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
+ position: absolute;
+ background-repeat: no-repeat;
+ background-position: center center;
+}
+.oo-ui-decoratedOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-decoratedOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ top: 0;
+ height: 100%;
+}
+.oo-ui-decoratedOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
+ width: 1.875em;
+ left: 0.5em;
+}
+.oo-ui-decoratedOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ width: 0.9375em;
+ right: 0.5em;
+}
+.oo-ui-decoratedOptionWidget.oo-ui-widget-disabled .oo-ui-iconElement-icon,
+.oo-ui-decoratedOptionWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-buttonSelectWidget {
+ display: inline-block;
+ white-space: nowrap;
+ border-radius: 2px;
+ margin-right: 0.5em;
+}
+.oo-ui-buttonSelectWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
+ border-radius: 0;
+ margin-left: -1px;
+}
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonElement-button {
+ border-bottom-left-radius: 2px;
+ border-top-left-radius: 2px;
+ margin-left: 0;
+}
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonElement-button {
+ border-bottom-right-radius: 2px;
+ border-top-right-radius: 2px;
+}
+.oo-ui-buttonOptionWidget {
+ display: inline-block;
+ padding: 0;
+ background-color: transparent;
+}
+.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
+ position: relative;
+}
+.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ position: static;
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
+ height: 1.875em;
+}
+.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
+ margin-top: 0;
+}
+.oo-ui-buttonOptionWidget.oo-ui-optionWidget-selected,
+.oo-ui-buttonOptionWidget.oo-ui-optionWidget-pressed,
+.oo-ui-buttonOptionWidget.oo-ui-optionWidget-highlighted {
+ background-color: transparent;
+}
+.oo-ui-buttonOptionWidget.oo-ui-widget-disabled .oo-ui-iconElement-icon,
+.oo-ui-buttonOptionWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
+ opacity: 1;
+}
+.oo-ui-radioOptionWidget {
+ cursor: default;
+ padding: 0.25em 0;
+ background-color: transparent;
+}
+.oo-ui-radioOptionWidget .oo-ui-radioInputWidget,
+.oo-ui-radioOptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-radioOptionWidget.oo-ui-optionWidget-selected,
+.oo-ui-radioOptionWidget.oo-ui-optionWidget-pressed,
+.oo-ui-radioOptionWidget.oo-ui-optionWidget-highlighted {
+ background-color: transparent;
+}
+.oo-ui-radioOptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ padding: 0.25em;
+ padding-left: 1em;
+}
+.oo-ui-radioOptionWidget .oo-ui-radioInputWidget {
+ margin-right: 0;
+}
+.oo-ui-labelWidget {
+ display: inline-block;
+}
+.oo-ui-iconWidget {
+ display: inline-block;
+ vertical-align: middle;
+ background-position: center center;
+ background-repeat: no-repeat;
+ line-height: 2.5em;
+ height: 1.875em;
+ width: 1.875em;
+}
+.oo-ui-iconWidget.oo-ui-widget-disabled {
+ opacity: 0.2;
+}
+.oo-ui-indicatorWidget {
+ display: inline-block;
+ vertical-align: middle;
+ background-position: center center;
+ background-repeat: no-repeat;
+ line-height: 2.5em;
+ height: 0.9375em;
+ width: 0.9375em;
+ margin: 0.46875em;
+}
+.oo-ui-indicatorWidget.oo-ui-widget-disabled {
+ opacity: 0.2;
+}
+.oo-ui-buttonWidget {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 0.5em;
+}
+.oo-ui-buttonWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-buttonGroupWidget {
+ display: inline-block;
+ white-space: nowrap;
+ border-radius: 2px;
+ margin-right: 0.5em;
+}
+.oo-ui-buttonGroupWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-buttonGroupWidget .oo-ui-buttonElement {
+ margin-right: 0;
+}
+.oo-ui-buttonGroupWidget .oo-ui-buttonElement:last-child {
+ margin-right: 0;
+}
+.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
+ border-radius: 0;
+ margin-left: -1px;
+}
+.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:first-child .oo-ui-buttonElement-button {
+ border-bottom-left-radius: 2px;
+ border-top-left-radius: 2px;
+ margin-left: 0;
+}
+.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:last-child .oo-ui-buttonElement-button {
+ border-bottom-right-radius: 2px;
+ border-top-right-radius: 2px;
+}
+.oo-ui-toggleButtonWidget {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 0.5em;
+}
+.oo-ui-toggleButtonWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-toggleSwitchWidget {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ overflow: hidden;
+ 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);
+ height: 2em;
+ width: 4em;
+ border-radius: 1em;
+ border: 1px #dddddd solid;
+ margin-right: 0.5em;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
+ cursor: default;
+}
+.oo-ui-toggleSwitchWidget-grip {
+ position: absolute;
+ display: block;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: 0;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
+ display: none;
+}
+.oo-ui-toggleSwitchWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-toggleSwitchWidget-grip {
+ top: 0.25em;
+ left: 0.25em;
+ width: 1.5em;
+ height: 1.5em;
+ margin-top: -1px;
+ border-radius: 1em;
+ border: 1px #dddddd solid;
+ background-color: #f7f7f7;
+ -webkit-transition: left 0.1s ease-in-out, margin-left 0.1s ease-in-out;
+ -moz-transition: left 0.1s ease-in-out, margin-left 0.1s ease-in-out;
+ -ms-transition: left 0.1s ease-in-out, margin-left 0.1s ease-in-out;
+ -o-transition: left 0.1s ease-in-out, margin-left 0.1s ease-in-out;
+ transition: left 0.1s ease-in-out, margin-left 0.1s ease-in-out;
+}
+.oo-ui-toggleSwitchWidget-glow {
+ border-radius: 1em;
+ background-color: #f7f7f7;
+ -webkit-transition: background-color 0.1s ease-in-out;
+ -moz-transition: background-color 0.1s ease-in-out;
+ -ms-transition: background-color 0.1s ease-in-out;
+ -o-transition: background-color 0.1s ease-in-out;
+ transition: background-color 0.1s ease-in-out;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
+ left: 2.25em;
+ margin-left: -2px;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
+ display: block;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
+ left: 0.25em;
+ margin-left: 0;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled {
+ border: 1px #cccccc solid;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover {
+ border-color: #aaaaaa;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled .oo-ui-toggleSwitchWidget-grip {
+ background-color: #ffffff;
+ border-color: #aaaaaa;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-glow {
+ background-color: #d0d0d0;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
+ background-color: #ffffff;
+}
+.oo-ui-progressBarWidget {
+ max-width: 50em;
+ border: 1px solid #cccccc;
+ border-radius: 0.1em;
+ overflow: hidden;
+}
+.oo-ui-progressBarWidget-bar {
+ height: 1em;
+ background: #dddddd;
+ -webkit-transition: width 200ms, margin-left 200ms;
+ -moz-transition: width 200ms, margin-left 200ms;
+ -ms-transition: width 200ms, margin-left 200ms;
+ -o-transition: width 200ms, margin-left 200ms;
+ transition: width 200ms, margin-left 200ms;
+}
+.oo-ui-progressBarWidget-indeterminate .oo-ui-progressBarWidget-bar {
+ -webkit-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+ -moz-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+ -ms-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+ -o-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+ animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+ width: 40%;
+ margin-left: -10%;
+ border-left-width: 1px;
+}
+.oo-ui-progressBarWidget.oo-ui-widget-disabled {
+ opacity: 0.6;
+}
+.oo-ui-actionWidget.oo-ui-pendingElement-pending {
+ background-image: /* @embed */ url(themes/mediawiki/images/textures/pending.gif);
+}
+.oo-ui-popupWidget {
+ position: absolute;
+ /* @noflip */
+ left: 0;
+}
+.oo-ui-popupWidget-popup {
+ position: relative;
+ overflow: hidden;
+ z-index: 1;
+}
+.oo-ui-popupWidget-anchor {
+ display: none;
+ z-index: 1;
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
+ display: block;
+ position: absolute;
+ top: 0;
+ /* @noflip */
+ left: 0;
+ background-repeat: no-repeat;
+}
+.oo-ui-popupWidget-head {
+ -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;
+}
+.oo-ui-popupWidget-head .oo-ui-labelElement-label {
+ float: left;
+ cursor: default;
+}
+.oo-ui-popupWidget-body {
+ clear: both;
+ overflow: hidden;
+}
+.oo-ui-popupWidget-popup {
+ border: 1px solid #aaaaaa;
+ border-radius: 0.2em;
+ background-color: #ffffff;
+ box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2);
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
+ margin-top: 9px;
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor:before,
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor:after {
+ content: "";
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-color: transparent;
+ border-top: 0;
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor:before {
+ bottom: -10px;
+ left: -9px;
+ border-bottom-color: #888888;
+ border-width: 10px;
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor:after {
+ bottom: -10px;
+ left: -8px;
+ border-bottom-color: #ffffff;
+ border-width: 9px;
+}
+.oo-ui-popupWidget-transitioning .oo-ui-popupWidget-popup {
+ -webkit-transition: width 0.1s ease-in-out, height 0.1s ease-in-out, left 0.1s ease-in-out;
+ -moz-transition: width 0.1s ease-in-out, height 0.1s ease-in-out, left 0.1s ease-in-out;
+ -ms-transition: width 0.1s ease-in-out, height 0.1s ease-in-out, left 0.1s ease-in-out;
+ -o-transition: width 0.1s ease-in-out, height 0.1s ease-in-out, left 0.1s ease-in-out;
+ transition: width 0.1s ease-in-out, height 0.1s ease-in-out, left 0.1s ease-in-out;
+}
+.oo-ui-popupWidget-head {
+ height: 2.5em;
+}
+.oo-ui-popupWidget-head .oo-ui-buttonWidget {
+ margin: 0.25em;
+}
+.oo-ui-popupWidget-head .oo-ui-labelElement-label {
+ margin: 0.75em 1em;
+}
+.oo-ui-popupWidget-body-padded {
+ padding: 0 1em;
+}
+.oo-ui-popupButtonWidget {
+ position: relative;
+}
+.oo-ui-popupButtonWidget .oo-ui-popupWidget {
+ position: absolute;
+ cursor: auto;
+}
+.oo-ui-popupButtonWidget.oo-ui-buttonElement-frameless > .oo-ui-popupWidget {
+ /* @noflip */
+ left: 1em;
+}
+.oo-ui-popupButtonWidget.oo-ui-buttonElement-framed > .oo-ui-popupWidget {
+ /* @noflip */
+ left: 1.75em;
+}
+.oo-ui-inputWidget {
+ margin-right: 0.5em;
+}
+.oo-ui-inputWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-buttonInputWidget {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-checkboxInputWidget {
+ position: relative;
+ line-height: 1.6em;
+ white-space: nowrap;
+}
+.oo-ui-checkboxInputWidget * {
+ font: inherit;
+ vertical-align: middle;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"] {
+ opacity: 0;
+ z-index: 1;
+ position: relative;
+ margin: 0;
+ width: 1.6em;
+ height: 1.6em;
+ max-width: none;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"] + span {
+ cursor: pointer;
+ -webkit-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -moz-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -ms-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -o-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ position: absolute;
+ left: 0;
+ border-radius: 2px;
+ width: 1.6em;
+ height: 1.6em;
+ background-color: white;
+ border: 1px solid #777777;
+ background-image: url("themes/mediawiki/images/icons/check-constructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-constructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-constructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check-constructive.png");
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-origin: border-box;
+ background-size: 0 0;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:checked + span {
+ background-size: 100% 100%;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:active + span {
+ background-color: #dddddd;
+ border-color: #dddddd;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:focus + span {
+ border-width: 2px;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:focus:hover + span,
+.oo-ui-checkboxInputWidget input[type="checkbox"]:hover + span {
+ border-bottom-width: 3px;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled + span {
+ cursor: default;
+ background-color: #eeeeee;
+ border-color: #eeeeee;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled:checked + span {
+ background-image: url("themes/mediawiki/images/icons/check-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check-invert.png");
+}
+.oo-ui-dropdownInputWidget {
+ position: relative;
+ vertical-align: middle;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ max-width: 50em;
+}
+.oo-ui-dropdownInputWidget select {
+ display: inline-block;
+ width: 100%;
+ resize: none;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-dropdownInputWidget select {
+ height: 2.5em;
+ padding: 0.5em;
+ font-size: inherit;
+ font-family: inherit;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ border: 1px solid #cccccc;
+}
+.oo-ui-dropdownInputWidget.oo-ui-widget-enabled select:hover,
+.oo-ui-dropdownInputWidget.oo-ui-widget-enabled select:focus {
+ border-color: #aaaaaa;
+ outline: none;
+}
+.oo-ui-dropdownInputWidget.oo-ui-widget-disabled select {
+ color: #cccccc;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.oo-ui-radioInputWidget {
+ position: relative;
+ line-height: 1.6em;
+ white-space: nowrap;
+}
+.oo-ui-radioInputWidget * {
+ font: inherit;
+ vertical-align: middle;
+}
+.oo-ui-radioInputWidget input[type="radio"] {
+ opacity: 0;
+ z-index: 1;
+ position: relative;
+ margin: 0;
+ width: 1.6em;
+ height: 1.6em;
+ max-width: none;
+}
+.oo-ui-radioInputWidget input[type="radio"] + span {
+ cursor: pointer;
+ -webkit-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -moz-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -ms-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -o-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ position: absolute;
+ left: 0;
+ border-radius: 100%;
+ width: 1.6em;
+ height: 1.6em;
+ background: white;
+ border: 1px solid #777777;
+ background-image: url("themes/mediawiki/images/icons/circle-constructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-constructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-constructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/circle-constructive.png");
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-origin: border-box;
+ background-size: 0 0;
+}
+.oo-ui-radioInputWidget input[type="radio"]:checked + span {
+ background-size: 100% 100%;
+}
+.oo-ui-radioInputWidget input[type="radio"]:active + span {
+ background-color: #dddddd;
+ border-color: #dddddd;
+}
+.oo-ui-radioInputWidget input[type="radio"]:focus + span {
+ border-width: 2px;
+}
+.oo-ui-radioInputWidget input[type="radio"]:focus:hover + span,
+.oo-ui-radioInputWidget input[type="radio"]:hover + span {
+ border-bottom-width: 3px;
+}
+.oo-ui-radioInputWidget input[type="radio"]:disabled + span {
+ cursor: default;
+ background-color: #eeeeee;
+ border-color: #eeeeee;
+}
+.oo-ui-radioInputWidget input[type="radio"]:disabled:checked + span {
+ background-image: url("themes/mediawiki/images/icons/circle-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/circle-invert.png");
+}
+.oo-ui-textInputWidget {
+ position: relative;
+ vertical-align: middle;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ max-width: 50em;
+}
+.oo-ui-textInputWidget input,
+.oo-ui-textInputWidget textarea {
+ display: inline-block;
+ width: 100%;
+ resize: none;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-textInputWidget > .oo-ui-iconElement-icon,
+.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator,
+.oo-ui-textInputWidget > .oo-ui-labelElement-label {
+ display: none;
+}
+.oo-ui-textInputWidget.oo-ui-iconElement > .oo-ui-iconElement-icon,
+.oo-ui-textInputWidget.oo-ui-indicatorElement > .oo-ui-indicatorElement-indicator {
+ display: block;
+ position: absolute;
+ top: 0;
+ height: 100%;
+ background-repeat: no-repeat;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-iconElement-icon,
+.oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
+ cursor: pointer;
+}
+.oo-ui-textInputWidget.oo-ui-labelElement > .oo-ui-labelElement-label {
+ display: block;
+}
+.oo-ui-textInputWidget > .oo-ui-iconElement-icon {
+ left: 0;
+}
+.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator {
+ right: 0;
+}
+.oo-ui-textInputWidget > .oo-ui-labelElement-label {
+ position: absolute;
+ top: 0;
+}
+.oo-ui-textInputWidget-labelPosition-after > .oo-ui-labelElement-label {
+ right: 0;
+}
+.oo-ui-textInputWidget-labelPosition-before > .oo-ui-labelElement-label {
+ left: 0;
+}
+.oo-ui-textInputWidget input,
+.oo-ui-textInputWidget textarea {
+ padding: 0.5em;
+ margin: 0;
+ font-size: inherit;
+ font-family: inherit;
+ background-color: #ffffff;
+ color: black;
+ border: solid 1px #cccccc;
+ box-shadow: inset 0 0 0 0 #347bff;
+ border-radius: 0.1em;
+ -webkit-transition: box-shadow 0.1s ease-in-out;
+ -moz-transition: box-shadow 0.1s ease-in-out;
+ -ms-transition: box-shadow 0.1s ease-in-out;
+ -o-transition: box-shadow 0.1s ease-in-out;
+ transition: box-shadow 0.1s ease-in-out;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-textInputWidget-decorated input,
+.oo-ui-textInputWidget-decorated textarea {
+ padding-left: 2em;
+}
+.oo-ui-textInputWidget-icon {
+ width: 2em;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled input,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea {
+ -webkit-transition: border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
+ -moz-transition: border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
+ -ms-transition: border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
+ -o-transition: border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
+ transition: border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled input:focus,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea:focus {
+ outline: none;
+ border-color: #347bff;
+ box-shadow: inset 0 0 0 0.1em #347bff;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled input[readonly],
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly] {
+ color: #777777;
+ text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled input[readonly]:focus,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly]:focus {
+ border-color: #cccccc;
+ box-shadow: inset 0 0 0 0.1em #cccccc;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid input,
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea {
+ border-color: red;
+ box-shadow: inset 0 0 0 0 red;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid input:focus,
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea:focus {
+ border-color: red;
+ box-shadow: inset 0 0 0 0.1em red;
+}
+.oo-ui-textInputWidget.oo-ui-widget-disabled input,
+.oo-ui-textInputWidget.oo-ui-widget-disabled textarea {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.oo-ui-textInputWidget.oo-ui-widget-disabled .oo-ui-iconElement-icon,
+.oo-ui-textInputWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-textInputWidget.oo-ui-widget-disabled .oo-ui-labelElement-label {
+ color: #dddddd;
+ text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-textInputWidget.oo-ui-pendingElement-pending input,
+.oo-ui-textInputWidget.oo-ui-pendingElement-pending textarea {
+ background-color: transparent;
+ background-image: /* @embed */ url(themes/mediawiki/images/textures/pending.gif);
+}
+.oo-ui-textInputWidget.oo-ui-iconElement input,
+.oo-ui-textInputWidget.oo-ui-iconElement textarea {
+ padding-left: 2.75em;
+}
+.oo-ui-textInputWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
+ left: 0.4em;
+ width: 1.875em;
+ margin-left: 0.1em;
+ height: 100%;
+ background-position: right center;
+}
+.oo-ui-textInputWidget.oo-ui-indicatorElement input,
+.oo-ui-textInputWidget.oo-ui-indicatorElement textarea {
+ padding-right: 1.875em;
+}
+.oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ width: 0.9375em;
+ margin: 0 0.775em;
+ height: 100%;
+}
+.oo-ui-textInputWidget > .oo-ui-labelElement-label {
+ padding: 0.4em;
+ line-height: 1.5em;
+ color: #888888;
+}
+.oo-ui-textInputWidget-labelPosition-after.oo-ui-indicatorElement > .oo-ui-labelElement-label {
+ margin-right: 2em;
+}
+.oo-ui-textInputWidget-labelPosition-before.oo-ui-iconElement > .oo-ui-labelElement-label {
+ margin-left: 2.5em;
+}
+.oo-ui-menuSelectWidget {
+ position: absolute;
+ background: #ffffff;
+ margin-top: -1px;
+ border: 1px solid #aaaaaa;
+ border-radius: 0 0 0.2em 0.2em;
+ padding-bottom: 0.25em;
+ box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2), 0 0.1em 0 0 rgba(0, 0, 0, 0.2);
+}
+.oo-ui-menuSelectWidget input {
+ position: absolute;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+ opacity: 0;
+}
+.oo-ui-menuOptionWidget {
+ position: relative;
+ padding: 0.5em 1em;
+}
+.oo-ui-menuOptionWidget .oo-ui-iconElement-icon {
+ display: none;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected {
+ background-color: transparent;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected .oo-ui-iconElement-icon {
+ display: block;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected {
+ background-color: #d8e6fe;
+ color: rgba(0, 0, 0, 0.8);
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected .oo-ui-iconElement-icon {
+ display: none;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted {
+ background-color: #eeeeee;
+ color: black;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted {
+ background-color: #d8e6fe;
+}
+.oo-ui-menuSectionOptionWidget {
+ cursor: default;
+ padding: 0.33em 0.75em;
+ color: #888888;
+}
+.oo-ui-dropdownWidget {
+ display: inline-block;
+ position: relative;
+ margin: 0.25em 0;
+ width: 100%;
+ max-width: 50em;
+ margin-right: 0.5em;
+}
+.oo-ui-dropdownWidget-handle {
+ width: 100%;
+ display: inline-block;
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator,
+.oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
+ position: absolute;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-dropdownWidget > .oo-ui-menuSelectWidget {
+ z-index: 1;
+ width: 100%;
+}
+.oo-ui-dropdownWidget.oo-ui-widget-disabled .oo-ui-dropdownWidget-handle {
+ cursor: default;
+}
+.oo-ui-dropdownWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-dropdownWidget-handle {
+ height: 2.5em;
+ border: 1px solid #cccccc;
+ border-radius: 0.1em;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator {
+ right: 0;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
+ left: 0.25em;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
+ line-height: 2.5em;
+ margin: 0 1em;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator {
+ top: 0;
+ width: 0.9375em;
+ height: 0.9375em;
+ margin: 0.775em;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
+ top: 0;
+ width: 1.875em;
+ height: 1.875em;
+ margin: 0.3em;
+}
+.oo-ui-dropdownWidget:hover .oo-ui-dropdownWidget-handle {
+ border-color: #aaaaaa;
+}
+.oo-ui-dropdownWidget.oo-ui-widget-disabled .oo-ui-dropdownWidget-handle {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.oo-ui-dropdownWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-dropdownWidget.oo-ui-iconElement .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
+ margin-left: 3em;
+}
+.oo-ui-dropdownWidget.oo-ui-indicatorElement .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
+ margin-right: 2em;
+}
+.oo-ui-dropdownWidget .oo-ui-selectWidget {
+ border-top-color: #ffffff;
+}
+.oo-ui-outlineOptionWidget {
+ position: relative;
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ font-size: 1.1em;
+ padding: 0.75em;
+}
+.oo-ui-outlineOptionWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
+ padding-right: 1.5em;
+}
+.oo-ui-outlineOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ opacity: 0.5;
+}
+.oo-ui-outlineOptionWidget-level-0 {
+ padding-left: 3.5em;
+}
+.oo-ui-outlineOptionWidget-level-0 .oo-ui-iconElement-icon {
+ left: 1em;
+}
+.oo-ui-outlineOptionWidget-level-1 {
+ padding-left: 5em;
+}
+.oo-ui-outlineOptionWidget-level-1 .oo-ui-iconElement-icon {
+ left: 2.5em;
+}
+.oo-ui-outlineOptionWidget-level-2 {
+ padding-left: 6.5em;
+}
+.oo-ui-outlineOptionWidget-level-2 .oo-ui-iconElement-icon {
+ left: 4em;
+}
+.oo-ui-selectWidget-depressed .oo-ui-outlineOptionWidget.oo-ui-optionWidget-selected {
+ background-color: #d0d0d0;
+ text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-important {
+ font-weight: bold;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-placeholder {
+ font-style: italic;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-empty .oo-ui-iconElement-icon {
+ opacity: 0.5;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-empty .oo-ui-labelElement-label {
+ color: #777777;
+}
+.oo-ui-outlineControlsWidget {
+ height: 3em;
+ background-color: #ffffff;
+}
+.oo-ui-outlineControlsWidget-items,
+.oo-ui-outlineControlsWidget-movers {
+ float: left;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
+ float: left;
+ background-position: right center;
+ background-repeat: no-repeat;
+}
+.oo-ui-outlineControlsWidget-items {
+ float: left;
+}
+.oo-ui-outlineControlsWidget-items .oo-ui-buttonWidget {
+ float: left;
+}
+.oo-ui-outlineControlsWidget-movers {
+ float: right;
+}
+.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
+ float: right;
+}
+.oo-ui-outlineControlsWidget-items,
+.oo-ui-outlineControlsWidget-movers {
+ height: 2em;
+ margin: 0.5em 0.5em 0.5em 0;
+ padding: 0;
+}
+.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
+ width: 1.5em;
+ height: 2em;
+ margin: 0.5em 0 0.5em 0.5em;
+ opacity: 0.2;
+}
+.oo-ui-tabSelectWidget {
+ text-align: left;
+ white-space: nowrap;
+ overflow: hidden;
+ background-color: #dddddd;
+}
+.oo-ui-tabOptionWidget {
+ display: inline-block;
+ vertical-align: bottom;
+ padding: 0.35em 1em;
+ margin: 0.5em 0 0 0.75em;
+ border: 1px solid transparent;
+ border-bottom: none;
+ border-top-left-radius: 2px;
+ border-top-right-radius: 2px;
+ color: #666666;
+ font-weight: bold;
+}
+.oo-ui-tabOptionWidget.oo-ui-widget-enabled:hover {
+ background-color: rgba(255, 255, 255, 0.3);
+}
+.oo-ui-tabOptionWidget.oo-ui-widget-enabled:active {
+ background-color: rgba(255, 255, 255, 0.8);
+}
+.oo-ui-tabOptionWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
+ padding-right: 1.5em;
+}
+.oo-ui-tabOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ opacity: 0.5;
+}
+.oo-ui-selectWidget-pressed .oo-ui-tabOptionWidget.oo-ui-optionWidget-selected,
+.oo-ui-selectWidget-depressed .oo-ui-tabOptionWidget.oo-ui-optionWidget-selected,
+.oo-ui-tabOptionWidget.oo-ui-optionWidget-selected:hover {
+ background-color: #ffffff;
+ color: #333333;
+}
+.oo-ui-comboBoxWidget {
+ display: inline-block;
+ position: relative;
+ width: 100%;
+ max-width: 50em;
+ margin-right: 0.5em;
+}
+.oo-ui-comboBoxWidget > .oo-ui-menuSelectWidget {
+ z-index: 1;
+ width: 100%;
+}
+.oo-ui-comboBoxWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-comboBoxWidget .oo-ui-textInputWidget input,
+.oo-ui-comboBoxWidget .oo-ui-textInputWidget textarea {
+ height: 2.35em;
+}
+.oo-ui-searchWidget-query {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+}
+.oo-ui-searchWidget-query .oo-ui-textInputWidget {
+ width: 100%;
+}
+.oo-ui-searchWidget-results {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.oo-ui-searchWidget-query {
+ height: 4em;
+ padding: 0 1em;
+ border-bottom: 1px solid #cccccc;
+}
+.oo-ui-searchWidget-query .oo-ui-textInputWidget {
+ margin: 0.75em 0;
+}
+.oo-ui-searchWidget-results {
+ top: 4em;
+ padding: 1em;
+ line-height: 0;
+}
+.oo-ui-window {
+ background: transparent;
+}
+.oo-ui-window-frame {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-window-content:focus {
+ outline: none;
+}
+.oo-ui-window-head,
+.oo-ui-window-foot {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.oo-ui-window-body {
+ margin: 0;
+ padding: 0;
+ background: none;
+}
+.oo-ui-window-overlay {
+ position: absolute;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+.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;
+ overflow: hidden;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-dialog-content > .oo-ui-window-head {
+ z-index: 1;
+ top: 0;
+}
+.oo-ui-dialog-content > .oo-ui-window-body {
+ z-index: 2;
+ top: 0;
+ bottom: 0;
+}
+.oo-ui-dialog-content > .oo-ui-window-foot {
+ z-index: 1;
+ bottom: 0;
+}
+.oo-ui-dialog-content > .oo-ui-window-body {
+ outline: 1px solid #aaaaaa;
+}
+.oo-ui-messageDialog-actions-horizontal {
+ display: table;
+ table-layout: fixed;
+ width: 100%;
+}
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+ display: table-cell;
+ width: 1%;
+}
+.oo-ui-messageDialog-actions-vertical {
+ display: block;
+}
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget {
+ position: relative;
+ text-align: center;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-buttonElement-button {
+ display: block;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labelElement-label {
+ position: relative;
+ top: auto;
+ bottom: auto;
+ display: inline;
+ white-space: nowrap;
+}
+.oo-ui-messageDialog-title,
+.oo-ui-messageDialog-message {
+ display: block;
+ text-align: center;
+ padding-top: 0.5em;
+}
+.oo-ui-messageDialog-title {
+ font-size: 1.5em;
+ line-height: 1em;
+ color: #000000;
+}
+.oo-ui-messageDialog-message {
+ font-size: 0.9em;
+ line-height: 1.25em;
+ color: #666666;
+}
+.oo-ui-messageDialog-message-verbose {
+ font-size: 1.1em;
+ line-height: 1.5em;
+ text-align: left;
+}
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+ border-right: 1px solid #e5e5e5;
+}
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
+ border-right-width: 0;
+}
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+ border-bottom: 1px solid #e5e5e5;
+}
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
+ border-bottom-width: 0;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget {
+ height: 3.4em;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ text-align: center;
+ line-height: 3.4em;
+ padding: 0 2em;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
+ background-color: rgba(0, 0, 0, 0.1);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
+ background-color: rgba(8, 126, 204, 0.05);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
+ background-color: rgba(8, 126, 204, 0.1);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
+ font-weight: bold;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
+ background-color: rgba(118, 171, 54, 0.05);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active {
+ background-color: rgba(118, 171, 54, 0.1);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover {
+ background-color: rgba(212, 83, 83, 0.05);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active {
+ background-color: rgba(212, 83, 83, 0.1);
+}
+.oo-ui-processDialog-location {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.oo-ui-processDialog-title {
+ display: inline;
+ padding: 0;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget {
+ white-space: nowrap;
+}
+.oo-ui-processDialog-actions-safe,
+.oo-ui-processDialog-actions-primary {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+}
+.oo-ui-processDialog-actions-safe {
+ left: 0;
+}
+.oo-ui-processDialog-actions-primary {
+ right: 0;
+}
+.oo-ui-processDialog-errors {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 2;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.oo-ui-processDialog-content .oo-ui-window-head {
+ height: 3.4em;
+}
+.oo-ui-processDialog-content .oo-ui-window-head.oo-ui-pendingElement-pending {
+ background-image: /* @embed */ url(themes/mediawiki/images/textures/pending.gif);
+}
+.oo-ui-processDialog-content .oo-ui-window-body {
+ top: 3.4em;
+ outline: 1px solid rgba(0, 0, 0, 0.2);
+}
+.oo-ui-processDialog-navigation {
+ position: relative;
+ height: 3.4em;
+ padding: 0 1em;
+}
+.oo-ui-processDialog-location {
+ padding: 0.75em 0;
+ height: 1.875em;
+ cursor: default;
+ text-align: center;
+}
+.oo-ui-processDialog-title {
+ font-weight: bold;
+ line-height: 1.875em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-buttonElement-button {
+ min-width: 1.875em;
+ min-height: 1.875em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-labelElement-label {
+ line-height: 1.875em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
+ margin-top: -0.125em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-framed {
+ margin: 0.75em 0 0.75em 0.75em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
+ padding: 0 1em;
+ vertical-align: middle;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:active {
+ background-color: rgba(0, 0, 0, 0.1);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed {
+ margin: 0.75em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
+ /* Adjust for border so text aligns with title */
+ margin: -1px;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
+ background-color: rgba(8, 126, 204, 0.05);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
+ background-color: rgba(8, 126, 204, 0.1);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
+ font-weight: bold;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
+ background-color: rgba(118, 171, 54, 0.05);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active {
+ background-color: rgba(118, 171, 54, 0.1);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover {
+ background-color: rgba(212, 83, 83, 0.05);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active {
+ background-color: rgba(212, 83, 83, 0.1);
+}
+.oo-ui-processDialog > .oo-ui-window-frame {
+ min-height: 5em;
+}
+.oo-ui-processDialog-errors {
+ background-color: rgba(255, 255, 255, 0.9);
+ padding: 3em 3em 1.5em 3em;
+ text-align: center;
+}
+.oo-ui-processDialog-errors .oo-ui-buttonWidget {
+ margin: 2em 1em 2em 1em;
+}
+.oo-ui-processDialog-errors-title {
+ font-size: 1.5em;
+ color: #000000;
+ margin-bottom: 2em;
+}
+.oo-ui-processDialog-error {
+ text-align: left;
+ margin: 1em;
+ padding: 1em;
+ border: 1px solid #ff9e9e;
+ background-color: #fff7f7;
+ border-radius: 0.25em;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+ position: fixed;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-active {
+ width: auto;
+ height: auto;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ padding: 1em;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame {
+ position: absolute;
+ right: 0;
+ left: 0;
+ margin: auto;
+ overflow: hidden;
+ max-width: 100%;
+ max-height: 100%;
+}
+.oo-ui-windowManager-fullscreen > .oo-ui-dialog > .oo-ui-window-frame {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ bottom: 0;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+ background-color: rgba(255, 255, 255, 0.5);
+ opacity: 0;
+ -webkit-transition: opacity 250ms ease-in-out;
+ -moz-transition: opacity 250ms ease-in-out;
+ -ms-transition: opacity 250ms ease-in-out;
+ -o-transition: opacity 250ms ease-in-out;
+ transition: opacity 250ms ease-in-out;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
+ top: 1em;
+ bottom: 1em;
+ background-color: #ffffff;
+ opacity: 0;
+ -webkit-transform: scale(0.5);
+ -moz-transform: scale(0.5);
+ -ms-transform: scale(0.5);
+ -o-transform: scale(0.5);
+ transform: scale(0.5);
+ -webkit-transition: all 250ms ease-in-out;
+ -moz-transition: all 250ms ease-in-out;
+ -ms-transition: all 250ms ease-in-out;
+ -o-transition: all 250ms ease-in-out;
+ transition: all 250ms ease-in-out;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
+ /* Fade window overlay */
+ opacity: 1;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
+ /* Fade frame */
+ opacity: 1;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1);
+}
+.oo-ui-windowManager-modal.oo-ui-windowManager-floating > .oo-ui-dialog > .oo-ui-window-frame {
+ border: 1px solid #aaaaaa;
+ border-radius: 0.2em;
+ box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2);
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki.css b/resources/lib/oojs-ui/oojs-ui-mediawiki.css
new file mode 100644
index 00000000..63569f6e
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki.css
@@ -0,0 +1,3204 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:44Z
+ */
+@-webkit-keyframes oo-ui-progressBarWidget-slide {
+ from {
+ margin-left: -40%;
+ }
+ to {
+ margin-left: 100%;
+ }
+}
+@-moz-keyframes oo-ui-progressBarWidget-slide {
+ from {
+ margin-left: -40%;
+ }
+ to {
+ margin-left: 100%;
+ }
+}
+@-ms-keyframes oo-ui-progressBarWidget-slide {
+ from {
+ margin-left: -40%;
+ }
+ to {
+ margin-left: 100%;
+ }
+}
+@-o-keyframes oo-ui-progressBarWidget-slide {
+ from {
+ margin-left: -40%;
+ }
+ to {
+ margin-left: 100%;
+ }
+}
+@keyframes oo-ui-progressBarWidget-slide {
+ from {
+ margin-left: -40%;
+ }
+ to {
+ margin-left: 100%;
+ }
+}
+/* @noflip */
+.oo-ui-rtl {
+ direction: rtl;
+}
+/* @noflip */
+.oo-ui-ltr {
+ direction: ltr;
+}
+.oo-ui-element-hidden {
+ display: none !important;
+}
+.oo-ui-buttonElement > .oo-ui-buttonElement-button {
+ cursor: pointer;
+ display: inline-block;
+ vertical-align: middle;
+ font: inherit;
+ white-space: nowrap;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon,
+.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ display: none;
+}
+.oo-ui-buttonElement.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
+ cursor: default;
+}
+.oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
+.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ display: inline-block;
+ vertical-align: middle;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-buttonElement-frameless {
+ display: inline-block;
+ position: relative;
+}
+.oo-ui-buttonElement-frameless.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
+ display: inline-block;
+ vertical-align: top;
+ text-align: center;
+}
+.oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ cursor: default;
+}
+.oo-ui-buttonElement > .oo-ui-buttonElement-button {
+ font-weight: bold;
+}
+.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ margin-left: 0;
+}
+.oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ width: 0.9375em;
+ height: 0.9375em;
+ margin: 0.46875em;
+}
+.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ margin-left: 0.46875em;
+}
+.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ width: 1.875em;
+ height: 1.875em;
+}
+.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2), 0 0 0 1px rgba(0, 0, 0, 0.2);
+ outline: none;
+}
+.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button .oo-ui-indicatorElement-indicator {
+ margin-right: 0;
+}
+.oo-ui-buttonElement-frameless.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ margin-left: 0.25em;
+ margin-right: 0.25em;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #555555;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #444444;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
+ color: #347bff;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #777777;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #1f4999;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
+ color: #00af89;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #777777;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #005946;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus > .oo-ui-labelElement-label {
+ color: #d11d13;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #777777;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active > .oo-ui-labelElement-label,
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ color: #73100a;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
+ color: #cccccc;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon,
+.oo-ui-buttonElement-frameless.oo-ui-widget-disabled > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
+ margin: 0.1em 0;
+ padding: 0.2em 0.8em;
+ border-radius: 2px;
+ -webkit-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+ -moz-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+ -ms-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+ -o-transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+ transition: background 0.1s ease-in-out, color 0.1s ease-in-out, box-shadow 0.1s ease-in-out;
+}
+.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button:focus {
+ outline: none;
+}
+.oo-ui-buttonElement-framed > input.oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ line-height: 1.875em;
+}
+.oo-ui-buttonElement-framed.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ margin-left: -0.5em;
+ margin-right: -0.5em;
+}
+.oo-ui-buttonElement-framed.oo-ui-iconElement.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ margin-right: 0.3em;
+}
+.oo-ui-buttonElement-framed.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ /* -0.5 - 0.475 */
+ margin-left: -0.005em;
+ margin-right: -0.005em;
+}
+.oo-ui-buttonElement-framed.oo-ui-indicatorElement.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
+.oo-ui-buttonElement-framed.oo-ui-indicatorElement.oo-ui-iconElement:not( .oo-ui-labelElement ) > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ margin-left: 0.46875em;
+ margin-right: -0.275em;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background: #dddddd;
+ border: 1px solid #dddddd;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
+ color: #555555;
+ background-color: #ffffff;
+ border: 1px solid #cdcdcd;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button:hover {
+ background-color: #ebebeb;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.2);
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ background-color: #d9d9d9;
+ border-color: #d9d9d9;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
+ color: #347bff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover {
+ background-color: rgba(52, 123, 255, 0.1);
+ border-color: rgba(31, 73, 153, 0.5);
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #1f4999;
+ border-color: #1f4999;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #1f4999;
+ border-color: #1f4999;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
+ color: #00af89;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover {
+ background-color: rgba(0, 171, 137, 0.1);
+ border-color: rgba(0, 89, 70, 0.5);
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #005946;
+ border-color: #005946;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #005946;
+ border-color: #005946;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
+ color: #d11d13;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover {
+ background-color: rgba(209, 29, 19, 0.1);
+ border-color: rgba(115, 16, 10, 0.5);
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #73100a;
+ border-color: #73100a;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #73100a;
+ border-color: #73100a;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #347bff;
+ border-color: #347bff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover {
+ background: #2962cc;
+ border-color: #2962cc;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #ffffff;
+ border-color: #347bff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #1f4999;
+ border-color: #1f4999;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #00af89;
+ border-color: #00af89;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:hover {
+ background: #008064;
+ border-color: #008064;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #ffffff;
+ border-color: #00af89;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #005946;
+ border-color: #005946;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-constructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #d11d13;
+ border-color: #d11d13;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:hover {
+ background: #8c130d;
+ border-color: #8c130d;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button:focus {
+ box-shadow: inset 0 0 0 1px #ffffff;
+ border-color: #d11d13;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ color: #ffffff;
+ background-color: #73100a;
+ border-color: #73100a;
+ box-shadow: none;
+}
+.oo-ui-buttonElement-framed.oo-ui-widget-enabled.oo-ui-flaggedElement-primary.oo-ui-flaggedElement-destructive.oo-ui-widget-enabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button {
+ background-color: #999999;
+ color: #ffffff;
+}
+.oo-ui-clippableElement-clippable {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-draggableElement {
+ cursor: -webkit-grab -moz-grab, url(images/grab.cur), move;
+ /*
+ * HACK: In order to style horizontally, we must override
+ * OO.ui.OptionWidget's display rule that is currently set
+ * to be 'block'
+ */
+}
+.oo-ui-draggableElement-dragging {
+ cursor: -webkit-grabbing -moz-grabbing, url(images/grabbing.cur), move;
+ background: rgba(0, 0, 0, 0.2);
+ opacity: 0.4;
+}
+.oo-ui-draggableGroupElement-horizontal .oo-ui-draggableElement.oo-ui-optionWidget {
+ display: inline-block;
+}
+.oo-ui-draggableGroupElement-placeholder {
+ position: absolute;
+ display: block;
+ background: rgba(0, 0, 0, 0.4);
+}
+.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-iconElement.oo-ui-iconElement-icon {
+ background-size: contain;
+ background-position: center center;
+}
+.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator,
+.oo-ui-indicatorElement.oo-ui-indicatorElement-indicator {
+ background-size: contain;
+ background-position: center center;
+}
+.oo-ui-lookupElement > .oo-ui-menuSelectWidget {
+ z-index: 1;
+ width: 100%;
+}
+.oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous > .oo-ui-panelLayout-scrollable {
+ overflow-y: hidden;
+}
+.oo-ui-bookletLayout-stackLayout > .oo-ui-panelLayout {
+ 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-editable > .oo-ui-outlineSelectWidget {
+ 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;
+}
+.oo-ui-bookletLayout-stackLayout > .oo-ui-panelLayout {
+ padding: 1.5em;
+}
+.oo-ui-bookletLayout-outlinePanel {
+ border-right: 1px solid #dddddd;
+}
+.oo-ui-bookletLayout-outlinePanel > .oo-ui-outlineControlsWidget {
+ box-shadow: 0 0 0.25em rgba(0, 0, 0, 0.25);
+}
+.oo-ui-indexLayout > .oo-ui-menuLayout-menu {
+ height: 3em;
+}
+.oo-ui-indexLayout > .oo-ui-menuLayout-content {
+ top: 3em;
+}
+.oo-ui-indexLayout-stackLayout > .oo-ui-panelLayout {
+ padding: 1.5em;
+}
+.oo-ui-fieldLayout {
+ display: block;
+ margin-bottom: 1em;
+}
+.oo-ui-fieldLayout:before,
+.oo-ui-fieldLayout:after {
+ content: " ";
+ display: table;
+}
+.oo-ui-fieldLayout:after {
+ clear: both;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+ display: block;
+ float: left;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ text-align: right;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body {
+ display: table;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+ display: table-cell;
+ vertical-align: middle;
+}
+.oo-ui-fieldLayout.oo-ui-labelElement.oo-ui-fieldLayout-align-top > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ display: inline-block;
+}
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help {
+ float: right;
+}
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+ z-index: 1;
+}
+.oo-ui-fieldLayout > .oo-ui-fieldLayout-help .oo-ui-fieldLayout-help-content {
+ padding: 0.5em 0.75em;
+ line-height: 1.5em;
+}
+.oo-ui-fieldLayout:last-child {
+ margin-bottom: 0;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ padding-top: 0.5em;
+ margin-right: 5%;
+ width: 35%;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field,
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+ width: 60%;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ padding: 0.5em;
+ padding-left: 1em;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-body > .oo-ui-fieldLayout-field {
+ padding: 0.5em 0;
+}
+.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ padding: 0.5em 0;
+}
+.oo-ui-fieldLayout > .oo-ui-popupButtonWidget {
+ margin-right: 0;
+ margin-top: 0.25em;
+}
+.oo-ui-fieldLayout > .oo-ui-popupButtonWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-fieldLayout-disabled .oo-ui-labelElement-label {
+ color: #cccccc;
+}
+.oo-ui-actionFieldLayout-field {
+ display: table;
+ table-layout: fixed;
+ width: 100%;
+}
+.oo-ui-actionFieldLayout-input,
+.oo-ui-actionFieldLayout-button {
+ display: table-cell;
+ vertical-align: middle;
+}
+.oo-ui-actionFieldLayout-input {
+ padding-right: 1em;
+}
+.oo-ui-actionFieldLayout-button {
+ width: 1%;
+ white-space: nowrap;
+}
+.oo-ui-fieldsetLayout {
+ position: relative;
+ margin: 0;
+ padding: 0;
+ border: none;
+}
+.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
+ display: block;
+ position: absolute;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-fieldsetLayout.oo-ui-labelElement > .oo-ui-labelElement-label {
+ display: inline-block;
+}
+.oo-ui-fieldsetLayout > .oo-ui-fieldsetLayout-help {
+ float: right;
+}
+.oo-ui-fieldsetLayout > .oo-ui-fieldsetLayout-help > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
+ z-index: 1;
+}
+.oo-ui-fieldsetLayout > .oo-ui-fieldsetLayout-help .oo-ui-fieldsetLayout-help-content {
+ padding: 0.5em 0.75em;
+ line-height: 1.5em;
+}
+.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout,
+.oo-ui-fieldsetLayout + .oo-ui-formLayout {
+ margin-top: 2em;
+}
+.oo-ui-fieldsetLayout > .oo-ui-labelElement-label {
+ font-size: 1.1em;
+ margin-bottom: 0.5em;
+ padding: 0.25em 0;
+ font-weight: bold;
+}
+.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-labelElement-label {
+ padding-left: 2em;
+ line-height: 1.8em;
+}
+.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
+ left: 0;
+ top: 0.25em;
+ width: 1.875em;
+ height: 1.875em;
+}
+.oo-ui-fieldsetLayout > .oo-ui-popupButtonWidget {
+ margin-right: 0;
+}
+.oo-ui-fieldsetLayout > .oo-ui-popupButtonWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-formLayout + .oo-ui-fieldsetLayout,
+.oo-ui-formLayout + .oo-ui-formLayout {
+ margin-top: 2em;
+}
+.oo-ui-menuLayout {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+.oo-ui-menuLayout-menu,
+.oo-ui-menuLayout-content {
+ position: absolute;
+ -webkit-transition: all ease-in-out 200ms;
+ -moz-transition: all ease-in-out 200ms;
+ -ms-transition: all ease-in-out 200ms;
+ -o-transition: all ease-in-out 200ms;
+ transition: all ease-in-out 200ms;
+}
+.oo-ui-menuLayout-menu {
+ height: 18em;
+ width: 18em;
+}
+.oo-ui-menuLayout-content {
+ top: 18em;
+ left: 18em;
+ right: 18em;
+ bottom: 18em;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-hideMenu .oo-ui-menuLayout-menu {
+ width: 0 !important;
+ height: 0 !important;
+ overflow: hidden;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-hideMenu .oo-ui-menuLayout-content {
+ top: 0 !important;
+ left: 0 !important;
+ right: 0 !important;
+ bottom: 0 !important;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-top .oo-ui-menuLayout-menu {
+ width: auto !important;
+ left: 0;
+ top: 0;
+ right: 0;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-top .oo-ui-menuLayout-content {
+ right: 0 !important;
+ bottom: 0 !important;
+ left: 0 !important;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-after .oo-ui-menuLayout-menu {
+ height: auto !important;
+ top: 0;
+ right: 0;
+ bottom: 0;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-after .oo-ui-menuLayout-content {
+ bottom: 0 !important;
+ left: 0 !important;
+ top: 0 !important;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-bottom .oo-ui-menuLayout-menu {
+ width: auto !important;
+ right: 0;
+ bottom: 0;
+ left: 0;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-bottom .oo-ui-menuLayout-content {
+ left: 0 !important;
+ top: 0 !important;
+ right: 0 !important;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-before .oo-ui-menuLayout-menu {
+ height: auto !important;
+ bottom: 0;
+ left: 0;
+ top: 0;
+}
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-before .oo-ui-menuLayout-content {
+ top: 0 !important;
+ right: 0 !important;
+ bottom: 0 !important;
+}
+.oo-ui-panelLayout {
+ position: relative;
+}
+.oo-ui-panelLayout-scrollable {
+ overflow-y: auto;
+}
+.oo-ui-panelLayout-expanded {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+}
+.oo-ui-panelLayout-padded {
+ padding: 1.25em;
+}
+.oo-ui-panelLayout-framed {
+ border: 1px solid #aaaaaa;
+ border-radius: 0.2em;
+ box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2);
+}
+.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
+ display: block;
+ position: relative;
+}
+.oo-ui-popupTool .oo-ui-popupWidget-popup,
+.oo-ui-popupTool .oo-ui-popupWidget-anchor {
+ z-index: 4;
+}
+.oo-ui-popupTool .oo-ui-popupWidget {
+ /* @noflip */
+ margin-left: 1.25em;
+}
+.oo-ui-toolGroupTool > .oo-ui-popupToolGroup {
+ border: 0;
+ border-radius: 0;
+ margin: 0;
+}
+.oo-ui-toolGroupTool > .oo-ui-toolGroup {
+ border-right: none;
+}
+.oo-ui-toolGroupTool > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle {
+ height: 2.5em;
+ padding: 0.3125em;
+}
+.oo-ui-toolGroupTool > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
+ height: 2.5em;
+ width: 1.875em;
+}
+.oo-ui-toolGroupTool > .oo-ui-popupToolGroup.oo-ui-labelElement > .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ line-height: 2.1em;
+}
+.oo-ui-toolGroup {
+ display: inline-block;
+ vertical-align: middle;
+ border-radius: 0;
+ border-right: 1px solid #dddddd;
+}
+.oo-ui-toolGroup-empty {
+ display: none;
+}
+.oo-ui-toolGroup .oo-ui-tool-link {
+ text-decoration: none;
+}
+.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-toolbar-narrow .oo-ui-toolGroup + .oo-ui-toolGroup {
+ margin-left: 0;
+}
+.oo-ui-toolGroup .oo-ui-toolGroup .oo-ui-widget-enabled {
+ border-right: none !important;
+}
+.oo-ui-barToolGroup > .oo-ui-iconElement-icon,
+.oo-ui-barToolGroup > .oo-ui-labelElement-label {
+ display: none;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
+ cursor: pointer;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool {
+ display: inline-block;
+ position: relative;
+ vertical-align: top;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
+ display: block;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-tool-accel {
+ display: none;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-iconElement > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ display: inline-block;
+ vertical-align: top;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-iconElement > .oo-ui-tool-link .oo-ui-tool-title {
+ display: none;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-iconElement.oo-ui-tool-with-label > .oo-ui-tool-link .oo-ui-tool-title {
+ display: inline;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link {
+ cursor: default;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
+ height: 1.875em;
+ padding: 0.625em;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ height: 1.875em;
+ width: 1.875em;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-tool-title {
+ line-height: 2.1em;
+ padding: 0 0.4em;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:hover {
+ border-color: rgba(0, 0, 0, 0.2);
+ background-color: #eeeeee;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-tool-title {
+ color: #555555;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled {
+ border-color: rgba(0, 0, 0, 0.2);
+ box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+ background-color: #e5e5e5;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled:hover {
+ background-color: #eeeeee;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
+ border-left-color: rgba(0, 0, 0, 0.1);
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-tool-title {
+ color: #cccccc;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.7;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:hover > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.9;
+}
+.oo-ui-barToolGroup.oo-ui-widget-enabled > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-enabled:active {
+ background-color: #e7e7e7;
+}
+.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-tool-title {
+ color: #cccccc;
+}
+.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool > a.oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-popupToolGroup {
+ position: relative;
+ height: 3.125em;
+ min-width: 2em;
+}
+.oo-ui-popupToolGroup-handle {
+ display: block;
+ cursor: pointer;
+}
+.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator,
+.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
+ position: absolute;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-popupToolGroup.oo-ui-widget-disabled .oo-ui-popupToolGroup-handle {
+ cursor: default;
+}
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
+ display: none;
+ position: absolute;
+ z-index: 4;
+}
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconElement-icon {
+ background-repeat: no-repeat;
+ background-position: center center;
+}
+.oo-ui-popupToolGroup-active.oo-ui-widget-enabled > .oo-ui-toolGroup-tools {
+ display: block;
+}
+.oo-ui-popupToolGroup-left > .oo-ui-toolGroup-tools {
+ left: 0;
+}
+.oo-ui-popupToolGroup-right > .oo-ui-toolGroup-tools {
+ right: 0;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link {
+ display: table;
+ width: 100%;
+ vertical-align: middle;
+ white-space: nowrap;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon,
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel,
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+ display: table-cell;
+ vertical-align: middle;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel {
+ text-align: right;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel:not(:empty) {
+ padding-left: 3em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup {
+ min-width: 1.875em;
+}
+.oo-ui-popupToolGroup.oo-ui-iconElement {
+ min-width: 3.125em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-iconElement {
+ min-width: 2.5em;
+}
+.oo-ui-popupToolGroup.oo-ui-indicatorElement.oo-ui-iconElement {
+ min-width: 4.375em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-indicatorElement.oo-ui-iconElement {
+ min-width: 3.75em;
+}
+.oo-ui-popupToolGroup.oo-ui-labelElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ line-height: 2.6em;
+ margin: 0 1em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-labelElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ margin: 0 0.5em;
+}
+.oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-iconElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ margin-left: 3em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-iconElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ margin-left: 2.5em;
+}
+.oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ margin-right: 2em;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup.oo-ui-labelElement.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
+ margin-right: 1.75em;
+}
+.oo-ui-popupToolGroup.oo-ui-widget-enabled .oo-ui-popupToolGroup-handle:hover {
+ background-color: #eeeeee;
+}
+.oo-ui-popupToolGroup.oo-ui-widget-enabled .oo-ui-popupToolGroup-handle:active {
+ background-color: #e5e5e5;
+}
+.oo-ui-popupToolGroup-handle {
+ padding: 0.3125em;
+ height: 2.5em;
+}
+.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
+ width: 0.9375em;
+ height: 1.625em;
+ margin: 0.78125em 0.5em;
+ top: 0;
+ right: 0;
+ opacity: 0.3;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
+ right: -0.3125em;
+}
+.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
+ width: 1.875em;
+ height: 2.6em;
+ margin: 0.25em;
+ top: 0;
+ left: 0.3125em;
+ opacity: 0.7;
+}
+.oo-ui-toolbar-narrow .oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
+ left: 0;
+}
+.oo-ui-popupToolGroup-header {
+ line-height: 2.6em;
+ margin: 0 0.6em;
+ font-weight: bold;
+}
+.oo-ui-popupToolGroup-active.oo-ui-widget-enabled {
+ border-bottom-left-radius: 0;
+ border-bottom-right-radius: 0;
+ box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+ background-color: #eeeeee;
+}
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
+ top: 3.125em;
+ margin: 0 -1px;
+ border: 1px solid #cccccc;
+ background-color: #ffffff;
+ box-shadow: 0 2px 3px rgba(0, 0, 0, 0.2);
+ min-width: 16em;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link {
+ padding: 0.4em 0.625em;
+ box-sizing: border-box;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
+ height: 2.5em;
+ width: 1.875em;
+ min-width: 1.875em;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+ padding-left: 0.5em;
+ color: #000000;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel,
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+ line-height: 2em;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel {
+ color: #888888;
+}
+.oo-ui-listToolGroup .oo-ui-tool {
+ display: block;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-listToolGroup .oo-ui-tool-link {
+ cursor: pointer;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+ cursor: default;
+}
+.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
+ border-color: rgba(0, 0, 0, 0.2);
+ background-color: #eeeeee;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:active {
+ background-color: #e7e7e7;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.9;
+}
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled {
+ border-color: rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0 0.07em 0.07em 0 rgba(0, 0, 0, 0.07);
+ background-color: #e5e5e5;
+}
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled + .oo-ui-tool-active.oo-ui-widget-enabled {
+ border-top-color: rgba(0, 0, 0, 0.1);
+}
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled:hover {
+ border-color: rgba(0, 0, 0, 0.2);
+ background-color: #eeeeee;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
+ color: #cccccc;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-accel {
+ color: #dddddd;
+}
+.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-listToolGroup.oo-ui-widget-disabled {
+ color: #cccccc;
+}
+.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
+.oo-ui-listToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-menuToolGroup .oo-ui-tool {
+ display: block;
+}
+.oo-ui-menuToolGroup .oo-ui-tool-link {
+ cursor: pointer;
+}
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
+ cursor: default;
+}
+.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
+ min-width: 10em;
+}
+.oo-ui-toolbar-narrow .oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
+ min-width: 8.125em;
+}
+.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
+ background-image: none;
+}
+.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconElement-icon {
+ background-image: url("themes/mediawiki/images/icons/check.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check.png");
+}
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
+ background-color: #eeeeee;
+}
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-tool-title {
+ color: #cccccc;
+}
+.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-menuToolGroup.oo-ui-widget-disabled {
+ color: #cccccc;
+}
+.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator,
+.oo-ui-menuToolGroup.oo-ui-widget-disabled .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-toolbar {
+ clear: both;
+}
+.oo-ui-toolbar-bar {
+ line-height: 1em;
+ position: relative;
+}
+.oo-ui-toolbar-actions {
+ float: right;
+}
+.oo-ui-toolbar-actions .oo-ui-toolbar {
+ display: inline-block;
+}
+.oo-ui-toolbar-tools {
+ display: inline;
+ white-space: nowrap;
+}
+.oo-ui-toolbar-narrow .oo-ui-toolbar-tools {
+ white-space: normal;
+}
+.oo-ui-toolbar-tools .oo-ui-tool {
+ white-space: normal;
+}
+.oo-ui-toolbar-tools,
+.oo-ui-toolbar-actions,
+.oo-ui-toolbar-shadow {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-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 {
+ background-position: left top;
+ background-repeat: repeat-x;
+ position: absolute;
+ width: 100%;
+ pointer-events: none;
+}
+.oo-ui-toolbar-bar {
+ border-bottom: 1px solid #cccccc;
+ background-color: #ffffff;
+ box-shadow: 0 1px 1px rgba(0, 0, 0, 0.1);
+ font-weight: 500;
+ color: #555555;
+}
+.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
+ border: none;
+ background: none;
+ box-shadow: none;
+}
+.oo-ui-toolbar-actions > .oo-ui-buttonElement {
+ margin-top: 0.25em;
+ margin-bottom: 0.25em;
+}
+.oo-ui-toolbar-actions > .oo-ui-toolbar,
+.oo-ui-toolbar-actions > .oo-ui-buttonElement:last-child {
+ margin-right: 0.5em;
+}
+.oo-ui-optionWidget {
+ position: relative;
+ display: block;
+ cursor: pointer;
+ padding: 0.25em 0.5em;
+ border: none;
+}
+.oo-ui-optionWidget.oo-ui-widget-disabled {
+ cursor: default;
+}
+.oo-ui-optionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ display: block;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+.oo-ui-optionWidget-highlighted {
+ background-color: #eeeeee;
+}
+.oo-ui-optionWidget .oo-ui-labelElement-label {
+ line-height: 1.5em;
+}
+.oo-ui-selectWidget-depressed .oo-ui-optionWidget-selected,
+.oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed,
+.oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed.oo-ui-optionWidget-highlighted,
+.oo-ui-selectWidget-pressed .oo-ui-optionWidget-pressed.oo-ui-optionWidget-highlighted.oo-ui-optionWidget-selected {
+ background-color: #d0d0d0;
+}
+.oo-ui-optionWidget.oo-ui-widget-disabled {
+ color: #cccccc;
+}
+.oo-ui-decoratedOptionWidget {
+ padding: 0.5em 2em 0.5em 3em;
+}
+.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon,
+.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
+ position: absolute;
+ background-repeat: no-repeat;
+ background-position: center center;
+}
+.oo-ui-decoratedOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-decoratedOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ top: 0;
+ height: 100%;
+}
+.oo-ui-decoratedOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
+ width: 1.875em;
+ left: 0.5em;
+}
+.oo-ui-decoratedOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ width: 0.9375em;
+ right: 0.5em;
+}
+.oo-ui-decoratedOptionWidget.oo-ui-widget-disabled .oo-ui-iconElement-icon,
+.oo-ui-decoratedOptionWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-buttonSelectWidget {
+ display: inline-block;
+ white-space: nowrap;
+ border-radius: 2px;
+ margin-right: 0.5em;
+}
+.oo-ui-buttonSelectWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
+ border-radius: 0;
+ margin-left: -1px;
+}
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:first-child .oo-ui-buttonElement-button {
+ border-bottom-left-radius: 2px;
+ border-top-left-radius: 2px;
+ margin-left: 0;
+}
+.oo-ui-buttonSelectWidget .oo-ui-buttonOptionWidget:last-child .oo-ui-buttonElement-button {
+ border-bottom-right-radius: 2px;
+ border-top-right-radius: 2px;
+}
+.oo-ui-buttonOptionWidget {
+ display: inline-block;
+ padding: 0;
+ background-color: transparent;
+}
+.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
+ position: relative;
+}
+.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ position: static;
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
+ height: 1.875em;
+}
+.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
+ margin-top: 0;
+}
+.oo-ui-buttonOptionWidget.oo-ui-optionWidget-selected,
+.oo-ui-buttonOptionWidget.oo-ui-optionWidget-pressed,
+.oo-ui-buttonOptionWidget.oo-ui-optionWidget-highlighted {
+ background-color: transparent;
+}
+.oo-ui-buttonOptionWidget.oo-ui-widget-disabled .oo-ui-iconElement-icon,
+.oo-ui-buttonOptionWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
+ opacity: 1;
+}
+.oo-ui-radioOptionWidget {
+ cursor: default;
+ padding: 0.25em 0;
+ background-color: transparent;
+}
+.oo-ui-radioOptionWidget .oo-ui-radioInputWidget,
+.oo-ui-radioOptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-radioOptionWidget.oo-ui-optionWidget-selected,
+.oo-ui-radioOptionWidget.oo-ui-optionWidget-pressed,
+.oo-ui-radioOptionWidget.oo-ui-optionWidget-highlighted {
+ background-color: transparent;
+}
+.oo-ui-radioOptionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ padding: 0.25em;
+ padding-left: 1em;
+}
+.oo-ui-radioOptionWidget .oo-ui-radioInputWidget {
+ margin-right: 0;
+}
+.oo-ui-labelWidget {
+ display: inline-block;
+}
+.oo-ui-iconWidget {
+ display: inline-block;
+ vertical-align: middle;
+ background-position: center center;
+ background-repeat: no-repeat;
+ line-height: 2.5em;
+ height: 1.875em;
+ width: 1.875em;
+}
+.oo-ui-iconWidget.oo-ui-widget-disabled {
+ opacity: 0.2;
+}
+.oo-ui-indicatorWidget {
+ display: inline-block;
+ vertical-align: middle;
+ background-position: center center;
+ background-repeat: no-repeat;
+ line-height: 2.5em;
+ height: 0.9375em;
+ width: 0.9375em;
+ margin: 0.46875em;
+}
+.oo-ui-indicatorWidget.oo-ui-widget-disabled {
+ opacity: 0.2;
+}
+.oo-ui-buttonWidget {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 0.5em;
+}
+.oo-ui-buttonWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-buttonGroupWidget {
+ display: inline-block;
+ white-space: nowrap;
+ border-radius: 2px;
+ margin-right: 0.5em;
+}
+.oo-ui-buttonGroupWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-buttonGroupWidget .oo-ui-buttonElement {
+ margin-right: 0;
+}
+.oo-ui-buttonGroupWidget .oo-ui-buttonElement:last-child {
+ margin-right: 0;
+}
+.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
+ border-radius: 0;
+ margin-left: -1px;
+}
+.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:first-child .oo-ui-buttonElement-button {
+ border-bottom-left-radius: 2px;
+ border-top-left-radius: 2px;
+ margin-left: 0;
+}
+.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:last-child .oo-ui-buttonElement-button {
+ border-bottom-right-radius: 2px;
+ border-top-right-radius: 2px;
+}
+.oo-ui-toggleButtonWidget {
+ display: inline-block;
+ vertical-align: middle;
+ margin-right: 0.5em;
+}
+.oo-ui-toggleButtonWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-toggleSwitchWidget {
+ position: relative;
+ display: inline-block;
+ vertical-align: middle;
+ overflow: hidden;
+ 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);
+ height: 2em;
+ width: 4em;
+ border-radius: 1em;
+ border: 1px #dddddd solid;
+ margin-right: 0.5em;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
+ cursor: default;
+}
+.oo-ui-toggleSwitchWidget-grip {
+ position: absolute;
+ display: block;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ right: 0;
+ left: 0;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
+ display: none;
+}
+.oo-ui-toggleSwitchWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-toggleSwitchWidget-grip {
+ top: 0.25em;
+ left: 0.25em;
+ width: 1.5em;
+ height: 1.5em;
+ margin-top: -1px;
+ border-radius: 1em;
+ border: 1px #dddddd solid;
+ background-color: #f7f7f7;
+ -webkit-transition: left 0.1s ease-in-out, margin-left 0.1s ease-in-out;
+ -moz-transition: left 0.1s ease-in-out, margin-left 0.1s ease-in-out;
+ -ms-transition: left 0.1s ease-in-out, margin-left 0.1s ease-in-out;
+ -o-transition: left 0.1s ease-in-out, margin-left 0.1s ease-in-out;
+ transition: left 0.1s ease-in-out, margin-left 0.1s ease-in-out;
+}
+.oo-ui-toggleSwitchWidget-glow {
+ border-radius: 1em;
+ background-color: #f7f7f7;
+ -webkit-transition: background-color 0.1s ease-in-out;
+ -moz-transition: background-color 0.1s ease-in-out;
+ -ms-transition: background-color 0.1s ease-in-out;
+ -o-transition: background-color 0.1s ease-in-out;
+ transition: background-color 0.1s ease-in-out;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
+ left: 2.25em;
+ margin-left: -2px;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
+ display: block;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
+ left: 0.25em;
+ margin-left: 0;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled {
+ border: 1px #cccccc solid;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover {
+ border-color: #aaaaaa;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled .oo-ui-toggleSwitchWidget-grip {
+ background-color: #ffffff;
+ border-color: #aaaaaa;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-glow {
+ background-color: #d0d0d0;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
+ background-color: #ffffff;
+}
+.oo-ui-progressBarWidget {
+ max-width: 50em;
+ border: 1px solid #cccccc;
+ border-radius: 0.1em;
+ overflow: hidden;
+}
+.oo-ui-progressBarWidget-bar {
+ height: 1em;
+ background: #dddddd;
+ -webkit-transition: width 200ms, margin-left 200ms;
+ -moz-transition: width 200ms, margin-left 200ms;
+ -ms-transition: width 200ms, margin-left 200ms;
+ -o-transition: width 200ms, margin-left 200ms;
+ transition: width 200ms, margin-left 200ms;
+}
+.oo-ui-progressBarWidget-indeterminate .oo-ui-progressBarWidget-bar {
+ -webkit-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+ -moz-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+ -ms-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+ -o-animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+ animation: oo-ui-progressBarWidget-slide 2s infinite linear;
+ width: 40%;
+ margin-left: -10%;
+ border-left-width: 1px;
+}
+.oo-ui-progressBarWidget.oo-ui-widget-disabled {
+ opacity: 0.6;
+}
+.oo-ui-actionWidget.oo-ui-pendingElement-pending {
+ background-image: /* @embed */ url(themes/mediawiki/images/textures/pending.gif);
+}
+.oo-ui-popupWidget {
+ position: absolute;
+ /* @noflip */
+ left: 0;
+}
+.oo-ui-popupWidget-popup {
+ position: relative;
+ overflow: hidden;
+ z-index: 1;
+}
+.oo-ui-popupWidget-anchor {
+ display: none;
+ z-index: 1;
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
+ display: block;
+ position: absolute;
+ top: 0;
+ /* @noflip */
+ left: 0;
+ background-repeat: no-repeat;
+}
+.oo-ui-popupWidget-head {
+ -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;
+}
+.oo-ui-popupWidget-head .oo-ui-labelElement-label {
+ float: left;
+ cursor: default;
+}
+.oo-ui-popupWidget-body {
+ clear: both;
+ overflow: hidden;
+}
+.oo-ui-popupWidget-popup {
+ border: 1px solid #aaaaaa;
+ border-radius: 0.2em;
+ background-color: #ffffff;
+ box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2);
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
+ margin-top: 9px;
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor:before,
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor:after {
+ content: "";
+ position: absolute;
+ width: 0;
+ height: 0;
+ border-style: solid;
+ border-color: transparent;
+ border-top: 0;
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor:before {
+ bottom: -10px;
+ left: -9px;
+ border-bottom-color: #888888;
+ border-width: 10px;
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor:after {
+ bottom: -10px;
+ left: -8px;
+ border-bottom-color: #ffffff;
+ border-width: 9px;
+}
+.oo-ui-popupWidget-transitioning .oo-ui-popupWidget-popup {
+ -webkit-transition: width 0.1s ease-in-out, height 0.1s ease-in-out, left 0.1s ease-in-out;
+ -moz-transition: width 0.1s ease-in-out, height 0.1s ease-in-out, left 0.1s ease-in-out;
+ -ms-transition: width 0.1s ease-in-out, height 0.1s ease-in-out, left 0.1s ease-in-out;
+ -o-transition: width 0.1s ease-in-out, height 0.1s ease-in-out, left 0.1s ease-in-out;
+ transition: width 0.1s ease-in-out, height 0.1s ease-in-out, left 0.1s ease-in-out;
+}
+.oo-ui-popupWidget-head {
+ height: 2.5em;
+}
+.oo-ui-popupWidget-head .oo-ui-buttonWidget {
+ margin: 0.25em;
+}
+.oo-ui-popupWidget-head .oo-ui-labelElement-label {
+ margin: 0.75em 1em;
+}
+.oo-ui-popupWidget-body-padded {
+ padding: 0 1em;
+}
+.oo-ui-popupButtonWidget {
+ position: relative;
+}
+.oo-ui-popupButtonWidget .oo-ui-popupWidget {
+ position: absolute;
+ cursor: auto;
+}
+.oo-ui-popupButtonWidget.oo-ui-buttonElement-frameless > .oo-ui-popupWidget {
+ /* @noflip */
+ left: 1em;
+}
+.oo-ui-popupButtonWidget.oo-ui-buttonElement-framed > .oo-ui-popupWidget {
+ /* @noflip */
+ left: 1.75em;
+}
+.oo-ui-inputWidget {
+ margin-right: 0.5em;
+}
+.oo-ui-inputWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-buttonInputWidget {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-checkboxInputWidget {
+ position: relative;
+ line-height: 1.6em;
+ white-space: nowrap;
+}
+.oo-ui-checkboxInputWidget * {
+ font: inherit;
+ vertical-align: middle;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"] {
+ opacity: 0;
+ z-index: 1;
+ position: relative;
+ margin: 0;
+ width: 1.6em;
+ height: 1.6em;
+ max-width: none;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"] + span {
+ cursor: pointer;
+ -webkit-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -moz-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -ms-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -o-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ position: absolute;
+ left: 0;
+ border-radius: 2px;
+ width: 1.6em;
+ height: 1.6em;
+ background-color: white;
+ border: 1px solid #777777;
+ background-image: url("themes/mediawiki/images/icons/check-constructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-constructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-constructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check-constructive.png");
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-origin: border-box;
+ background-size: 0 0;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:checked + span {
+ background-size: 100% 100%;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:active + span {
+ background-color: #dddddd;
+ border-color: #dddddd;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:focus + span {
+ border-width: 2px;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:focus:hover + span,
+.oo-ui-checkboxInputWidget input[type="checkbox"]:hover + span {
+ border-bottom-width: 3px;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled + span {
+ cursor: default;
+ background-color: #eeeeee;
+ border-color: #eeeeee;
+}
+.oo-ui-checkboxInputWidget input[type="checkbox"]:disabled:checked + span {
+ background-image: url("themes/mediawiki/images/icons/check-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check-invert.png");
+}
+.oo-ui-dropdownInputWidget {
+ position: relative;
+ vertical-align: middle;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ max-width: 50em;
+}
+.oo-ui-dropdownInputWidget select {
+ display: inline-block;
+ width: 100%;
+ resize: none;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-dropdownInputWidget select {
+ height: 2.5em;
+ padding: 0.5em;
+ font-size: inherit;
+ font-family: inherit;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ border: 1px solid #cccccc;
+}
+.oo-ui-dropdownInputWidget.oo-ui-widget-enabled select:hover,
+.oo-ui-dropdownInputWidget.oo-ui-widget-enabled select:focus {
+ border-color: #aaaaaa;
+ outline: none;
+}
+.oo-ui-dropdownInputWidget.oo-ui-widget-disabled select {
+ color: #cccccc;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.oo-ui-radioInputWidget {
+ position: relative;
+ line-height: 1.6em;
+ white-space: nowrap;
+}
+.oo-ui-radioInputWidget * {
+ font: inherit;
+ vertical-align: middle;
+}
+.oo-ui-radioInputWidget input[type="radio"] {
+ opacity: 0;
+ z-index: 1;
+ position: relative;
+ margin: 0;
+ width: 1.6em;
+ height: 1.6em;
+ max-width: none;
+}
+.oo-ui-radioInputWidget input[type="radio"] + span {
+ cursor: pointer;
+ -webkit-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -moz-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -ms-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -o-transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ transition: background-size 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ position: absolute;
+ left: 0;
+ border-radius: 100%;
+ width: 1.6em;
+ height: 1.6em;
+ background: white;
+ border: 1px solid #777777;
+ background-image: url("themes/mediawiki/images/icons/circle-constructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-constructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-constructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/circle-constructive.png");
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-origin: border-box;
+ background-size: 0 0;
+}
+.oo-ui-radioInputWidget input[type="radio"]:checked + span {
+ background-size: 100% 100%;
+}
+.oo-ui-radioInputWidget input[type="radio"]:active + span {
+ background-color: #dddddd;
+ border-color: #dddddd;
+}
+.oo-ui-radioInputWidget input[type="radio"]:focus + span {
+ border-width: 2px;
+}
+.oo-ui-radioInputWidget input[type="radio"]:focus:hover + span,
+.oo-ui-radioInputWidget input[type="radio"]:hover + span {
+ border-bottom-width: 3px;
+}
+.oo-ui-radioInputWidget input[type="radio"]:disabled + span {
+ cursor: default;
+ background-color: #eeeeee;
+ border-color: #eeeeee;
+}
+.oo-ui-radioInputWidget input[type="radio"]:disabled:checked + span {
+ background-image: url("themes/mediawiki/images/icons/circle-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/circle-invert.png");
+}
+.oo-ui-textInputWidget {
+ position: relative;
+ vertical-align: middle;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ width: 100%;
+ max-width: 50em;
+}
+.oo-ui-textInputWidget input,
+.oo-ui-textInputWidget textarea {
+ display: inline-block;
+ width: 100%;
+ resize: none;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-textInputWidget > .oo-ui-iconElement-icon,
+.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator,
+.oo-ui-textInputWidget > .oo-ui-labelElement-label {
+ display: none;
+}
+.oo-ui-textInputWidget.oo-ui-iconElement > .oo-ui-iconElement-icon,
+.oo-ui-textInputWidget.oo-ui-indicatorElement > .oo-ui-indicatorElement-indicator {
+ display: block;
+ position: absolute;
+ top: 0;
+ height: 100%;
+ background-repeat: no-repeat;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-iconElement-icon,
+.oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
+ cursor: pointer;
+}
+.oo-ui-textInputWidget.oo-ui-labelElement > .oo-ui-labelElement-label {
+ display: block;
+}
+.oo-ui-textInputWidget > .oo-ui-iconElement-icon {
+ left: 0;
+}
+.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator {
+ right: 0;
+}
+.oo-ui-textInputWidget > .oo-ui-labelElement-label {
+ position: absolute;
+ top: 0;
+}
+.oo-ui-textInputWidget-labelPosition-after > .oo-ui-labelElement-label {
+ right: 0;
+}
+.oo-ui-textInputWidget-labelPosition-before > .oo-ui-labelElement-label {
+ left: 0;
+}
+.oo-ui-textInputWidget input,
+.oo-ui-textInputWidget textarea {
+ padding: 0.5em;
+ margin: 0;
+ font-size: inherit;
+ font-family: inherit;
+ background-color: #ffffff;
+ color: black;
+ border: solid 1px #cccccc;
+ box-shadow: inset 0 0 0 0 #347bff;
+ border-radius: 0.1em;
+ -webkit-transition: box-shadow 0.1s ease-in-out;
+ -moz-transition: box-shadow 0.1s ease-in-out;
+ -ms-transition: box-shadow 0.1s ease-in-out;
+ -o-transition: box-shadow 0.1s ease-in-out;
+ transition: box-shadow 0.1s ease-in-out;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-textInputWidget-decorated input,
+.oo-ui-textInputWidget-decorated textarea {
+ padding-left: 2em;
+}
+.oo-ui-textInputWidget-icon {
+ width: 2em;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled input,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea {
+ -webkit-transition: border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
+ -moz-transition: border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
+ -ms-transition: border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
+ -o-transition: border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
+ transition: border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1);
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled input:focus,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea:focus {
+ outline: none;
+ border-color: #347bff;
+ box-shadow: inset 0 0 0 0.1em #347bff;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled input[readonly],
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly] {
+ color: #777777;
+ text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled input[readonly]:focus,
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly]:focus {
+ border-color: #cccccc;
+ box-shadow: inset 0 0 0 0.1em #cccccc;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid input,
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea {
+ border-color: red;
+ box-shadow: inset 0 0 0 0 red;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid input:focus,
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea:focus {
+ border-color: red;
+ box-shadow: inset 0 0 0 0.1em red;
+}
+.oo-ui-textInputWidget.oo-ui-widget-disabled input,
+.oo-ui-textInputWidget.oo-ui-widget-disabled textarea {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.oo-ui-textInputWidget.oo-ui-widget-disabled .oo-ui-iconElement-icon,
+.oo-ui-textInputWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-textInputWidget.oo-ui-widget-disabled .oo-ui-labelElement-label {
+ color: #dddddd;
+ text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-textInputWidget.oo-ui-pendingElement-pending input,
+.oo-ui-textInputWidget.oo-ui-pendingElement-pending textarea {
+ background-color: transparent;
+ background-image: /* @embed */ url(themes/mediawiki/images/textures/pending.gif);
+}
+.oo-ui-textInputWidget.oo-ui-iconElement input,
+.oo-ui-textInputWidget.oo-ui-iconElement textarea {
+ padding-left: 2.75em;
+}
+.oo-ui-textInputWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
+ left: 0.4em;
+ width: 1.875em;
+ margin-left: 0.1em;
+ height: 100%;
+ background-position: right center;
+}
+.oo-ui-textInputWidget.oo-ui-indicatorElement input,
+.oo-ui-textInputWidget.oo-ui-indicatorElement textarea {
+ padding-right: 1.875em;
+}
+.oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ width: 0.9375em;
+ margin: 0 0.775em;
+ height: 100%;
+}
+.oo-ui-textInputWidget > .oo-ui-labelElement-label {
+ padding: 0.4em;
+ line-height: 1.5em;
+ color: #888888;
+}
+.oo-ui-textInputWidget-labelPosition-after.oo-ui-indicatorElement > .oo-ui-labelElement-label {
+ margin-right: 2em;
+}
+.oo-ui-textInputWidget-labelPosition-before.oo-ui-iconElement > .oo-ui-labelElement-label {
+ margin-left: 2.5em;
+}
+.oo-ui-menuSelectWidget {
+ position: absolute;
+ background: #ffffff;
+ margin-top: -1px;
+ border: 1px solid #aaaaaa;
+ border-radius: 0 0 0.2em 0.2em;
+ padding-bottom: 0.25em;
+ box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2), 0 0.1em 0 0 rgba(0, 0, 0, 0.2);
+}
+.oo-ui-menuSelectWidget input {
+ position: absolute;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+ opacity: 0;
+}
+.oo-ui-menuOptionWidget {
+ position: relative;
+ padding: 0.5em 1em;
+}
+.oo-ui-menuOptionWidget .oo-ui-iconElement-icon {
+ display: none;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected {
+ background-color: transparent;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected .oo-ui-iconElement-icon {
+ display: block;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected {
+ background-color: #d8e6fe;
+ color: rgba(0, 0, 0, 0.8);
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected .oo-ui-iconElement-icon {
+ display: none;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted {
+ background-color: #eeeeee;
+ color: black;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-selected.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted {
+ background-color: #d8e6fe;
+}
+.oo-ui-menuSectionOptionWidget {
+ cursor: default;
+ padding: 0.33em 0.75em;
+ color: #888888;
+}
+.oo-ui-dropdownWidget {
+ display: inline-block;
+ position: relative;
+ margin: 0.25em 0;
+ width: 100%;
+ max-width: 50em;
+ margin-right: 0.5em;
+}
+.oo-ui-dropdownWidget-handle {
+ width: 100%;
+ display: inline-block;
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator,
+.oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
+ position: absolute;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-dropdownWidget > .oo-ui-menuSelectWidget {
+ z-index: 1;
+ width: 100%;
+}
+.oo-ui-dropdownWidget.oo-ui-widget-disabled .oo-ui-dropdownWidget-handle {
+ cursor: default;
+}
+.oo-ui-dropdownWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-dropdownWidget-handle {
+ height: 2.5em;
+ border: 1px solid #cccccc;
+ border-radius: 0.1em;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator {
+ right: 0;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
+ left: 0.25em;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
+ line-height: 2.5em;
+ margin: 0 1em;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator {
+ top: 0;
+ width: 0.9375em;
+ height: 0.9375em;
+ margin: 0.775em;
+}
+.oo-ui-dropdownWidget-handle .oo-ui-iconElement-icon {
+ top: 0;
+ width: 1.875em;
+ height: 1.875em;
+ margin: 0.3em;
+}
+.oo-ui-dropdownWidget:hover .oo-ui-dropdownWidget-handle {
+ border-color: #aaaaaa;
+}
+.oo-ui-dropdownWidget.oo-ui-widget-disabled .oo-ui-dropdownWidget-handle {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.oo-ui-dropdownWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-dropdownWidget.oo-ui-iconElement .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
+ margin-left: 3em;
+}
+.oo-ui-dropdownWidget.oo-ui-indicatorElement .oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
+ margin-right: 2em;
+}
+.oo-ui-dropdownWidget .oo-ui-selectWidget {
+ border-top-color: #ffffff;
+}
+.oo-ui-outlineOptionWidget {
+ position: relative;
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ font-size: 1.1em;
+ padding: 0.75em;
+}
+.oo-ui-outlineOptionWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
+ padding-right: 1.5em;
+}
+.oo-ui-outlineOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ opacity: 0.5;
+}
+.oo-ui-outlineOptionWidget-level-0 {
+ padding-left: 3.5em;
+}
+.oo-ui-outlineOptionWidget-level-0 .oo-ui-iconElement-icon {
+ left: 1em;
+}
+.oo-ui-outlineOptionWidget-level-1 {
+ padding-left: 5em;
+}
+.oo-ui-outlineOptionWidget-level-1 .oo-ui-iconElement-icon {
+ left: 2.5em;
+}
+.oo-ui-outlineOptionWidget-level-2 {
+ padding-left: 6.5em;
+}
+.oo-ui-outlineOptionWidget-level-2 .oo-ui-iconElement-icon {
+ left: 4em;
+}
+.oo-ui-selectWidget-depressed .oo-ui-outlineOptionWidget.oo-ui-optionWidget-selected {
+ background-color: #d0d0d0;
+ text-shadow: 0 1px 1px #ffffff;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-important {
+ font-weight: bold;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-placeholder {
+ font-style: italic;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-empty .oo-ui-iconElement-icon {
+ opacity: 0.5;
+}
+.oo-ui-outlineOptionWidget.oo-ui-flaggedElement-empty .oo-ui-labelElement-label {
+ color: #777777;
+}
+.oo-ui-outlineControlsWidget {
+ height: 3em;
+ background-color: #ffffff;
+}
+.oo-ui-outlineControlsWidget-items,
+.oo-ui-outlineControlsWidget-movers {
+ float: left;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
+ float: left;
+ background-position: right center;
+ background-repeat: no-repeat;
+}
+.oo-ui-outlineControlsWidget-items {
+ float: left;
+}
+.oo-ui-outlineControlsWidget-items .oo-ui-buttonWidget {
+ float: left;
+}
+.oo-ui-outlineControlsWidget-movers {
+ float: right;
+}
+.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
+ float: right;
+}
+.oo-ui-outlineControlsWidget-items,
+.oo-ui-outlineControlsWidget-movers {
+ height: 2em;
+ margin: 0.5em 0.5em 0.5em 0;
+ padding: 0;
+}
+.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
+ width: 1.5em;
+ height: 2em;
+ margin: 0.5em 0 0.5em 0.5em;
+ opacity: 0.2;
+}
+.oo-ui-tabSelectWidget {
+ text-align: left;
+ white-space: nowrap;
+ overflow: hidden;
+ background-color: #dddddd;
+}
+.oo-ui-tabOptionWidget {
+ display: inline-block;
+ vertical-align: bottom;
+ padding: 0.35em 1em;
+ margin: 0.5em 0 0 0.75em;
+ border: 1px solid transparent;
+ border-bottom: none;
+ border-top-left-radius: 2px;
+ border-top-right-radius: 2px;
+ color: #666666;
+ font-weight: bold;
+}
+.oo-ui-tabOptionWidget.oo-ui-widget-enabled:hover {
+ background-color: rgba(255, 255, 255, 0.3);
+}
+.oo-ui-tabOptionWidget.oo-ui-widget-enabled:active {
+ background-color: rgba(255, 255, 255, 0.8);
+}
+.oo-ui-tabOptionWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
+ padding-right: 1.5em;
+}
+.oo-ui-tabOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ opacity: 0.5;
+}
+.oo-ui-selectWidget-pressed .oo-ui-tabOptionWidget.oo-ui-optionWidget-selected,
+.oo-ui-selectWidget-depressed .oo-ui-tabOptionWidget.oo-ui-optionWidget-selected,
+.oo-ui-tabOptionWidget.oo-ui-optionWidget-selected:hover {
+ background-color: #ffffff;
+ color: #333333;
+}
+.oo-ui-comboBoxWidget {
+ display: inline-block;
+ position: relative;
+ width: 100%;
+ max-width: 50em;
+ margin-right: 0.5em;
+}
+.oo-ui-comboBoxWidget > .oo-ui-menuSelectWidget {
+ z-index: 1;
+ width: 100%;
+}
+.oo-ui-comboBoxWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-comboBoxWidget .oo-ui-textInputWidget input,
+.oo-ui-comboBoxWidget .oo-ui-textInputWidget textarea {
+ height: 2.35em;
+}
+.oo-ui-searchWidget-query {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+}
+.oo-ui-searchWidget-query .oo-ui-textInputWidget {
+ width: 100%;
+}
+.oo-ui-searchWidget-results {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.oo-ui-searchWidget-query {
+ height: 4em;
+ padding: 0 1em;
+ border-bottom: 1px solid #cccccc;
+}
+.oo-ui-searchWidget-query .oo-ui-textInputWidget {
+ margin: 0.75em 0;
+}
+.oo-ui-searchWidget-results {
+ top: 4em;
+ padding: 1em;
+ line-height: 0;
+}
+.oo-ui-window {
+ background: transparent;
+}
+.oo-ui-window-frame {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-window-content:focus {
+ outline: none;
+}
+.oo-ui-window-head,
+.oo-ui-window-foot {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.oo-ui-window-body {
+ margin: 0;
+ padding: 0;
+ background: none;
+}
+.oo-ui-window-overlay {
+ position: absolute;
+ top: 0;
+ /* @noflip */
+ left: 0;
+}
+.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;
+ overflow: hidden;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-dialog-content > .oo-ui-window-head {
+ z-index: 1;
+ top: 0;
+}
+.oo-ui-dialog-content > .oo-ui-window-body {
+ z-index: 2;
+ top: 0;
+ bottom: 0;
+}
+.oo-ui-dialog-content > .oo-ui-window-foot {
+ z-index: 1;
+ bottom: 0;
+}
+.oo-ui-dialog-content > .oo-ui-window-body {
+ outline: 1px solid #aaaaaa;
+}
+.oo-ui-messageDialog-actions-horizontal {
+ display: table;
+ table-layout: fixed;
+ width: 100%;
+}
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+ display: table-cell;
+ width: 1%;
+}
+.oo-ui-messageDialog-actions-vertical {
+ display: block;
+}
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+ display: block;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget {
+ position: relative;
+ text-align: center;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-buttonElement-button {
+ display: block;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labelElement-label {
+ position: relative;
+ top: auto;
+ bottom: auto;
+ display: inline;
+ white-space: nowrap;
+}
+.oo-ui-messageDialog-title,
+.oo-ui-messageDialog-message {
+ display: block;
+ text-align: center;
+ padding-top: 0.5em;
+}
+.oo-ui-messageDialog-title {
+ font-size: 1.5em;
+ line-height: 1em;
+ color: #000000;
+}
+.oo-ui-messageDialog-message {
+ font-size: 0.9em;
+ line-height: 1.25em;
+ color: #666666;
+}
+.oo-ui-messageDialog-message-verbose {
+ font-size: 1.1em;
+ line-height: 1.5em;
+ text-align: left;
+}
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
+ border-right: 1px solid #e5e5e5;
+}
+.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
+ border-right-width: 0;
+}
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
+ border-bottom: 1px solid #e5e5e5;
+}
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
+ border-bottom-width: 0;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget {
+ height: 3.4em;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ text-align: center;
+ line-height: 3.4em;
+ padding: 0 2em;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
+ background-color: rgba(0, 0, 0, 0.1);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
+ background-color: rgba(8, 126, 204, 0.05);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
+ background-color: rgba(8, 126, 204, 0.1);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
+ font-weight: bold;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
+ background-color: rgba(118, 171, 54, 0.05);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active {
+ background-color: rgba(118, 171, 54, 0.1);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover {
+ background-color: rgba(212, 83, 83, 0.05);
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active {
+ background-color: rgba(212, 83, 83, 0.1);
+}
+.oo-ui-processDialog-location {
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+.oo-ui-processDialog-title {
+ display: inline;
+ padding: 0;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget {
+ white-space: nowrap;
+}
+.oo-ui-processDialog-actions-safe,
+.oo-ui-processDialog-actions-primary {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+}
+.oo-ui-processDialog-actions-safe {
+ left: 0;
+}
+.oo-ui-processDialog-actions-primary {
+ right: 0;
+}
+.oo-ui-processDialog-errors {
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ z-index: 2;
+ overflow-x: hidden;
+ overflow-y: auto;
+}
+.oo-ui-processDialog-content .oo-ui-window-head {
+ height: 3.4em;
+}
+.oo-ui-processDialog-content .oo-ui-window-head.oo-ui-pendingElement-pending {
+ background-image: /* @embed */ url(themes/mediawiki/images/textures/pending.gif);
+}
+.oo-ui-processDialog-content .oo-ui-window-body {
+ top: 3.4em;
+ outline: 1px solid rgba(0, 0, 0, 0.2);
+}
+.oo-ui-processDialog-navigation {
+ position: relative;
+ height: 3.4em;
+ padding: 0 1em;
+}
+.oo-ui-processDialog-location {
+ padding: 0.75em 0;
+ height: 1.875em;
+ cursor: default;
+ text-align: center;
+}
+.oo-ui-processDialog-title {
+ font-weight: bold;
+ line-height: 1.875em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-buttonElement-button {
+ min-width: 1.875em;
+ min-height: 1.875em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-labelElement-label {
+ line-height: 1.875em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
+ margin-top: -0.125em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-framed {
+ margin: 0.75em 0 0.75em 0.75em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
+ padding: 0 1em;
+ vertical-align: middle;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:hover {
+ background-color: rgba(0, 0, 0, 0.05);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:active {
+ background-color: rgba(0, 0, 0, 0.1);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed {
+ margin: 0.75em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
+ /* Adjust for border so text aligns with title */
+ margin: -1px;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:hover {
+ background-color: rgba(8, 126, 204, 0.05);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive:active {
+ background-color: rgba(8, 126, 204, 0.1);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label {
+ font-weight: bold;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
+ background-color: rgba(118, 171, 54, 0.05);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active {
+ background-color: rgba(118, 171, 54, 0.1);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover {
+ background-color: rgba(212, 83, 83, 0.05);
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active {
+ background-color: rgba(212, 83, 83, 0.1);
+}
+.oo-ui-processDialog > .oo-ui-window-frame {
+ min-height: 5em;
+}
+.oo-ui-processDialog-errors {
+ background-color: rgba(255, 255, 255, 0.9);
+ padding: 3em 3em 1.5em 3em;
+ text-align: center;
+}
+.oo-ui-processDialog-errors .oo-ui-buttonWidget {
+ margin: 2em 1em 2em 1em;
+}
+.oo-ui-processDialog-errors-title {
+ font-size: 1.5em;
+ color: #000000;
+ margin-bottom: 2em;
+}
+.oo-ui-processDialog-error {
+ text-align: left;
+ margin: 1em;
+ padding: 1em;
+ border: 1px solid #ff9e9e;
+ background-color: #fff7f7;
+ border-radius: 0.25em;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+ position: fixed;
+ width: 0;
+ height: 0;
+ overflow: hidden;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-active {
+ width: auto;
+ height: auto;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ padding: 1em;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame {
+ position: absolute;
+ right: 0;
+ left: 0;
+ margin: auto;
+ overflow: hidden;
+ max-width: 100%;
+ max-height: 100%;
+}
+.oo-ui-windowManager-fullscreen > .oo-ui-dialog > .oo-ui-window-frame {
+ width: 100%;
+ height: 100%;
+ top: 0;
+ bottom: 0;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog {
+ background-color: rgba(255, 255, 255, 0.5);
+ opacity: 0;
+ -webkit-transition: opacity 250ms ease-in-out;
+ -moz-transition: opacity 250ms ease-in-out;
+ -ms-transition: opacity 250ms ease-in-out;
+ -o-transition: opacity 250ms ease-in-out;
+ transition: opacity 250ms ease-in-out;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
+ top: 1em;
+ bottom: 1em;
+ background-color: #ffffff;
+ opacity: 0;
+ -webkit-transform: scale(0.5);
+ -moz-transform: scale(0.5);
+ -ms-transform: scale(0.5);
+ -o-transform: scale(0.5);
+ transform: scale(0.5);
+ -webkit-transition: all 250ms ease-in-out;
+ -moz-transition: all 250ms ease-in-out;
+ -ms-transition: all 250ms ease-in-out;
+ -o-transition: all 250ms ease-in-out;
+ transition: all 250ms ease-in-out;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
+ /* Fade window overlay */
+ opacity: 1;
+}
+.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
+ /* Fade frame */
+ opacity: 1;
+ -webkit-transform: scale(1);
+ -moz-transform: scale(1);
+ -ms-transform: scale(1);
+ -o-transform: scale(1);
+ transform: scale(1);
+}
+.oo-ui-windowManager-modal.oo-ui-windowManager-floating > .oo-ui-dialog > .oo-ui-window-frame {
+ border: 1px solid #aaaaaa;
+ border-radius: 0.2em;
+ box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2);
+}
+
+.oo-ui-icon-add {
+ background-image: url("themes/mediawiki/images/icons/add.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/add.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/add.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/add.png");
+}
+.oo-ui-image-constructive .oo-ui-icon-add,
+.oo-ui-image-constructive.oo-ui-icon-add {
+ background-image: url("themes/mediawiki/images/icons/add-constructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/add-constructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/add-constructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/add-constructive.png");
+}
+.oo-ui-image-invert .oo-ui-icon-add,
+.oo-ui-image-invert.oo-ui-icon-add {
+ background-image: url("themes/mediawiki/images/icons/add-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/add-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/add-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/add-invert.png");
+}
+.oo-ui-icon-advanced {
+ background-image: url("themes/mediawiki/images/icons/advanced.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/advanced.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/advanced.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/advanced.png");
+}
+.oo-ui-image-invert .oo-ui-icon-advanced,
+.oo-ui-image-invert.oo-ui-icon-advanced {
+ background-image: url("themes/mediawiki/images/icons/advanced-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/advanced-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/advanced-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/advanced-invert.png");
+}
+.oo-ui-icon-alert {
+ background-image: url("themes/mediawiki/images/icons/alert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/alert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/alert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/alert.png");
+}
+.oo-ui-image-warning .oo-ui-icon-alert,
+.oo-ui-image-warning.oo-ui-icon-alert {
+ background-image: url("themes/mediawiki/images/icons/alert-warning.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/alert-warning.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/alert-warning.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/alert-warning.png");
+}
+.oo-ui-image-invert .oo-ui-icon-alert,
+.oo-ui-image-invert.oo-ui-icon-alert {
+ background-image: url("themes/mediawiki/images/icons/alert-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/alert-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/alert-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/alert-invert.png");
+}
+.oo-ui-icon-cancel {
+ background-image: url("themes/mediawiki/images/icons/cancel.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/cancel.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/cancel.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/cancel.png");
+}
+.oo-ui-image-invert .oo-ui-icon-cancel,
+.oo-ui-image-invert.oo-ui-icon-cancel {
+ background-image: url("themes/mediawiki/images/icons/cancel-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/cancel-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/cancel-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/cancel-invert.png");
+}
+.oo-ui-icon-check {
+ background-image: url("themes/mediawiki/images/icons/check.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check.png");
+}
+.oo-ui-image-constructive .oo-ui-icon-check,
+.oo-ui-image-constructive.oo-ui-icon-check {
+ background-image: url("themes/mediawiki/images/icons/check-constructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-constructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-constructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check-constructive.png");
+}
+.oo-ui-image-progressive .oo-ui-icon-check,
+.oo-ui-image-progressive.oo-ui-icon-check {
+ background-image: url("themes/mediawiki/images/icons/check-progressive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-progressive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-progressive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check-progressive.png");
+}
+.oo-ui-image-invert .oo-ui-icon-check,
+.oo-ui-image-invert.oo-ui-icon-check {
+ background-image: url("themes/mediawiki/images/icons/check-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/check-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/check-invert.png");
+}
+.oo-ui-icon-circle {
+ background-image: url("themes/mediawiki/images/icons/circle.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/circle.png");
+}
+.oo-ui-image-constructive .oo-ui-icon-circle,
+.oo-ui-image-constructive.oo-ui-icon-circle {
+ background-image: url("themes/mediawiki/images/icons/circle-constructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-constructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-constructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/circle-constructive.png");
+}
+.oo-ui-image-invert .oo-ui-icon-circle,
+.oo-ui-image-invert.oo-ui-icon-circle {
+ background-image: url("themes/mediawiki/images/icons/circle-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/circle-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/circle-invert.png");
+}
+.oo-ui-icon-close {
+ background-image: url("themes/mediawiki/images/icons/close-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/close-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/close-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/close-ltr.png");
+}
+.oo-ui-image-invert .oo-ui-icon-close,
+.oo-ui-image-invert.oo-ui-icon-close {
+ background-image: url("themes/mediawiki/images/icons/close-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/close-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/close-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/close-ltr-invert.png");
+}
+.oo-ui-icon-code {
+ background-image: url("themes/mediawiki/images/icons/code.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/code.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/code.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/code.png");
+}
+.oo-ui-image-invert .oo-ui-icon-code,
+.oo-ui-image-invert.oo-ui-icon-code {
+ background-image: url("themes/mediawiki/images/icons/code-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/code-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/code-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/code-invert.png");
+}
+.oo-ui-icon-collapse {
+ background-image: url("themes/mediawiki/images/icons/collapse.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/collapse.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/collapse.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/collapse.png");
+}
+.oo-ui-image-invert .oo-ui-icon-collapse,
+.oo-ui-image-invert.oo-ui-icon-collapse {
+ background-image: url("themes/mediawiki/images/icons/collapse-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/collapse-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/collapse-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/collapse-invert.png");
+}
+.oo-ui-icon-comment {
+ background-image: url("themes/mediawiki/images/icons/comment.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/comment.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/comment.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/comment.png");
+}
+.oo-ui-image-invert .oo-ui-icon-comment,
+.oo-ui-image-invert.oo-ui-icon-comment {
+ background-image: url("themes/mediawiki/images/icons/comment-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/comment-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/comment-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/comment-invert.png");
+}
+.oo-ui-icon-ellipsis {
+ background-image: url("themes/mediawiki/images/icons/ellipsis.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/ellipsis.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/ellipsis.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/ellipsis.png");
+}
+.oo-ui-image-invert .oo-ui-icon-ellipsis,
+.oo-ui-image-invert.oo-ui-icon-ellipsis {
+ background-image: url("themes/mediawiki/images/icons/ellipsis-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/ellipsis-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/ellipsis-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/ellipsis-invert.png");
+}
+.oo-ui-icon-expand {
+ background-image: url("themes/mediawiki/images/icons/expand.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/expand.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/expand.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/expand.png");
+}
+.oo-ui-image-invert .oo-ui-icon-expand,
+.oo-ui-image-invert.oo-ui-icon-expand {
+ background-image: url("themes/mediawiki/images/icons/expand-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/expand-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/expand-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/expand-invert.png");
+}
+.oo-ui-icon-help {
+ background-image: url("themes/mediawiki/images/icons/help-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/help-ltr.png");
+}
+/* @noflip */
+.oo-ui-icon-help:lang(he) {
+ background-image: url("themes/mediawiki/images/icons/help-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/help-ltr.png");
+}
+/* @noflip */
+.oo-ui-icon-help:lang(yi) {
+ background-image: url("themes/mediawiki/images/icons/help-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/help-ltr.png");
+}
+.oo-ui-image-invert .oo-ui-icon-help,
+.oo-ui-image-invert.oo-ui-icon-help {
+ background-image: url("themes/mediawiki/images/icons/help-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/help-ltr-invert.png");
+}
+/* @noflip */
+.oo-ui-image-invert .oo-ui-icon-help:lang(he),
+.oo-ui-image-invert.oo-ui-icon-help:lang(he) {
+ background-image: url("themes/mediawiki/images/icons/help-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/help-ltr-invert.png");
+}
+/* @noflip */
+.oo-ui-image-invert .oo-ui-icon-help:lang(yi),
+.oo-ui-image-invert.oo-ui-icon-help:lang(yi) {
+ background-image: url("themes/mediawiki/images/icons/help-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/help-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/help-ltr-invert.png");
+}
+.oo-ui-icon-history {
+ background-image: url("themes/mediawiki/images/icons/history.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/history.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/history.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/history.png");
+}
+.oo-ui-image-invert .oo-ui-icon-history,
+.oo-ui-image-invert.oo-ui-icon-history {
+ background-image: url("themes/mediawiki/images/icons/history-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/history-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/history-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/history-invert.png");
+}
+.oo-ui-icon-info {
+ background-image: url("themes/mediawiki/images/icons/info.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/info.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/info.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/info.png");
+}
+.oo-ui-image-invert .oo-ui-icon-info,
+.oo-ui-image-invert.oo-ui-icon-info {
+ background-image: url("themes/mediawiki/images/icons/info-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/info-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/info-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/info-invert.png");
+}
+.oo-ui-icon-menu {
+ background-image: url("themes/mediawiki/images/icons/menu.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/menu.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/menu.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/menu.png");
+}
+.oo-ui-image-invert .oo-ui-icon-menu,
+.oo-ui-image-invert.oo-ui-icon-menu {
+ background-image: url("themes/mediawiki/images/icons/menu-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/menu-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/menu-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/menu-invert.png");
+}
+.oo-ui-icon-next {
+ background-image: url("themes/mediawiki/images/icons/move-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/move-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/move-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/move-ltr.png");
+}
+.oo-ui-image-invert .oo-ui-icon-next,
+.oo-ui-image-invert.oo-ui-icon-next {
+ background-image: url("themes/mediawiki/images/icons/move-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/move-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/move-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/move-ltr-invert.png");
+}
+.oo-ui-icon-picture {
+ background-image: url("themes/mediawiki/images/icons/picture.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/picture.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/picture.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/picture.png");
+}
+.oo-ui-image-invert .oo-ui-icon-picture,
+.oo-ui-image-invert.oo-ui-icon-picture {
+ background-image: url("themes/mediawiki/images/icons/picture-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/picture-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/picture-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/picture-invert.png");
+}
+.oo-ui-icon-previous {
+ background-image: url("themes/mediawiki/images/icons/move-rtl.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/move-rtl.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/move-rtl.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/move-rtl.png");
+}
+.oo-ui-image-invert .oo-ui-icon-previous,
+.oo-ui-image-invert.oo-ui-icon-previous {
+ background-image: url("themes/mediawiki/images/icons/move-rtl-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/move-rtl-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/move-rtl-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/move-rtl-invert.png");
+}
+.oo-ui-icon-redo {
+ background-image: url("themes/mediawiki/images/icons/arched-arrow-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arched-arrow-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arched-arrow-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/arched-arrow-ltr.png");
+}
+.oo-ui-image-invert .oo-ui-icon-redo,
+.oo-ui-image-invert.oo-ui-icon-redo {
+ background-image: url("themes/mediawiki/images/icons/arched-arrow-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arched-arrow-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arched-arrow-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/arched-arrow-ltr-invert.png");
+}
+.oo-ui-icon-remove {
+ background-image: url("themes/mediawiki/images/icons/remove.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/remove.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/remove.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/remove.png");
+}
+.oo-ui-image-destructive .oo-ui-icon-remove,
+.oo-ui-image-destructive.oo-ui-icon-remove {
+ background-image: url("themes/mediawiki/images/icons/remove-destructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/remove-destructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/remove-destructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/remove-destructive.png");
+}
+.oo-ui-image-invert .oo-ui-icon-remove,
+.oo-ui-image-invert.oo-ui-icon-remove {
+ background-image: url("themes/mediawiki/images/icons/remove-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/remove-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/remove-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/remove-invert.png");
+}
+.oo-ui-icon-search {
+ background-image: url("themes/mediawiki/images/icons/search-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/search-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/search-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/search-ltr.png");
+}
+.oo-ui-image-invert .oo-ui-icon-search,
+.oo-ui-image-invert.oo-ui-icon-search {
+ background-image: url("themes/mediawiki/images/icons/search-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/search-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/search-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/search-ltr-invert.png");
+}
+.oo-ui-icon-settings {
+ background-image: url("themes/mediawiki/images/icons/settings.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/settings.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/settings.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/settings.png");
+}
+.oo-ui-image-invert .oo-ui-icon-settings,
+.oo-ui-image-invert.oo-ui-icon-settings {
+ background-image: url("themes/mediawiki/images/icons/settings-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/settings-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/settings-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/settings-invert.png");
+}
+.oo-ui-icon-tag {
+ background-image: url("themes/mediawiki/images/icons/tag.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/tag.png");
+}
+.oo-ui-image-destructive .oo-ui-icon-tag,
+.oo-ui-image-destructive.oo-ui-icon-tag {
+ background-image: url("themes/mediawiki/images/icons/tag-destructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag-destructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag-destructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/tag-destructive.png");
+}
+.oo-ui-image-warning .oo-ui-icon-tag,
+.oo-ui-image-warning.oo-ui-icon-tag {
+ background-image: url("themes/mediawiki/images/icons/tag-warning.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag-warning.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag-warning.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/tag-warning.png");
+}
+.oo-ui-image-constructive .oo-ui-icon-tag,
+.oo-ui-image-constructive.oo-ui-icon-tag {
+ background-image: url("themes/mediawiki/images/icons/tag-constructive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag-constructive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag-constructive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/tag-constructive.png");
+}
+.oo-ui-image-progressive .oo-ui-icon-tag,
+.oo-ui-image-progressive.oo-ui-icon-tag {
+ background-image: url("themes/mediawiki/images/icons/tag-progressive.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag-progressive.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag-progressive.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/tag-progressive.png");
+}
+.oo-ui-image-invert .oo-ui-icon-tag,
+.oo-ui-image-invert.oo-ui-icon-tag {
+ background-image: url("themes/mediawiki/images/icons/tag-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/tag-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/tag-invert.png");
+}
+.oo-ui-icon-undo {
+ background-image: url("themes/mediawiki/images/icons/arched-arrow-rtl.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arched-arrow-rtl.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arched-arrow-rtl.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/arched-arrow-rtl.png");
+}
+.oo-ui-image-invert .oo-ui-icon-undo,
+.oo-ui-image-invert.oo-ui-icon-undo {
+ background-image: url("themes/mediawiki/images/icons/arched-arrow-rtl-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arched-arrow-rtl-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/arched-arrow-rtl-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/arched-arrow-rtl-invert.png");
+}
+.oo-ui-icon-window {
+ background-image: url("themes/mediawiki/images/icons/window.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/window.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/window.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/window.png");
+}
+.oo-ui-image-invert .oo-ui-icon-window,
+.oo-ui-image-invert.oo-ui-icon-window {
+ background-image: url("themes/mediawiki/images/icons/window-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/window-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/icons/window-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/icons/window-invert.png");
+}
+
+.oo-ui-indicator-alert {
+ background-image: url("themes/mediawiki/images/indicators/alert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/alert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/alert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/alert.png");
+}
+.oo-ui-image-invert .oo-ui-indicator-alert,
+.oo-ui-image-invert.oo-ui-indicator-alert {
+ background-image: url("themes/mediawiki/images/indicators/alert-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/alert-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/alert-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/alert-invert.png");
+}
+.oo-ui-indicator-up {
+ background-image: url("themes/mediawiki/images/indicators/arrow-up.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-up.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-up.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/arrow-up.png");
+}
+.oo-ui-image-invert .oo-ui-indicator-up,
+.oo-ui-image-invert.oo-ui-indicator-up {
+ background-image: url("themes/mediawiki/images/indicators/arrow-up-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-up-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-up-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/arrow-up-invert.png");
+}
+.oo-ui-indicator-down {
+ background-image: url("themes/mediawiki/images/indicators/arrow-down.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-down.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-down.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/arrow-down.png");
+}
+.oo-ui-image-invert .oo-ui-indicator-down,
+.oo-ui-image-invert.oo-ui-indicator-down {
+ background-image: url("themes/mediawiki/images/indicators/arrow-down-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-down-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-down-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/arrow-down-invert.png");
+}
+.oo-ui-indicator-next {
+ background-image: url("themes/mediawiki/images/indicators/arrow-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/arrow-ltr.png");
+}
+.oo-ui-image-invert .oo-ui-indicator-next,
+.oo-ui-image-invert.oo-ui-indicator-next {
+ background-image: url("themes/mediawiki/images/indicators/arrow-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/arrow-ltr-invert.png");
+}
+.oo-ui-indicator-previous {
+ background-image: url("themes/mediawiki/images/indicators/arrow-rtl.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-rtl.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-rtl.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/arrow-rtl.png");
+}
+.oo-ui-image-invert .oo-ui-indicator-previous,
+.oo-ui-image-invert.oo-ui-indicator-previous {
+ background-image: url("themes/mediawiki/images/indicators/arrow-rtl-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-rtl-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/arrow-rtl-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/arrow-rtl-invert.png");
+}
+.oo-ui-indicator-required {
+ background-image: url("themes/mediawiki/images/indicators/required.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/required.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/required.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/required.png");
+}
+.oo-ui-image-invert .oo-ui-indicator-required,
+.oo-ui-image-invert.oo-ui-indicator-required {
+ background-image: url("themes/mediawiki/images/indicators/required-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/required-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/required-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/required-invert.png");
+}
+.oo-ui-indicator-search {
+ background-image: url("themes/mediawiki/images/indicators/search-ltr.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/search-ltr.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/search-ltr.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/search-ltr.png");
+}
+.oo-ui-image-invert .oo-ui-indicator-search,
+.oo-ui-image-invert.oo-ui-indicator-search {
+ background-image: url("themes/mediawiki/images/indicators/search-ltr-invert.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/search-ltr-invert.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/indicators/search-ltr-invert.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/indicators/search-ltr-invert.png");
+}
+
+.oo-ui-texture-pending {
+ background-image: url("themes/mediawiki/images/textures/pending.gif");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/textures/pending.gif");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/textures/pending.gif");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/textures/pending.gif");
+}
+.oo-ui-texture-transparency {
+ background-image: url("themes/mediawiki/images/textures/transparency.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/textures/transparency.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/mediawiki/images/textures/transparency.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/mediawiki/images/textures/transparency.png");
+}
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki.js b/resources/lib/oojs-ui/oojs-ui-mediawiki.js
new file mode 100644
index 00000000..eaca1f15
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki.js
@@ -0,0 +1,66 @@
+/*!
+ * OOjs UI v0.11.3
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-05-12T12:15:37Z
+ */
+/**
+ * @class
+ * @extends OO.ui.Theme
+ *
+ * @constructor
+ */
+OO.ui.MediaWikiTheme = function OoUiMediaWikiTheme() {
+ // Parent constructor
+ OO.ui.MediaWikiTheme.super.call( this );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.MediaWikiTheme, OO.ui.Theme );
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+OO.ui.MediaWikiTheme.prototype.getElementClasses = function ( element ) {
+ // Parent method
+ var variant,
+ variants = {
+ warning: false,
+ invert: false,
+ progressive: false,
+ constructive: false,
+ destructive: false
+ },
+ // Parent method
+ classes = OO.ui.MediaWikiTheme.super.prototype.getElementClasses.call( this, element ),
+ isFramed;
+
+ if ( element.supports( [ 'hasFlag' ] ) ) {
+ isFramed = element.supports( [ 'isFramed' ] ) && element.isFramed();
+ if ( isFramed && ( element.isDisabled() || element.hasFlag( 'primary' ) ) ) {
+ variants.invert = true;
+ } else {
+ variants.progressive = element.hasFlag( 'progressive' );
+ variants.constructive = element.hasFlag( 'constructive' );
+ variants.destructive = element.hasFlag( 'destructive' );
+ variants.warning = element.hasFlag( 'warning' );
+ }
+ }
+
+ for ( variant in variants ) {
+ classes[ variants[ variant ] ? 'on' : 'off' ].push( 'oo-ui-image-' + variant );
+ }
+
+ return classes;
+};
+
+/* Instantiation */
+
+OO.ui.theme = new OO.ui.MediaWikiTheme();
diff --git a/resources/lib/oojs-ui/oojs-ui-minerva.css b/resources/lib/oojs-ui/oojs-ui-minerva.css
deleted file mode 100644
index 36492c05..00000000
--- a/resources/lib/oojs-ui/oojs-ui-minerva.css
+++ /dev/null
@@ -1,1397 +0,0 @@
-/*!
- * OOjs UI v0.1.0-pre (f2c3f12959)
- * 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: 2014-09-18T23:22:20Z
- */
-/*
- * Blank theme mixins.
- *
- * Base styles invoke these mixins at the end of their definitions. Override these mixins to add
- * additional rules to the base styles.
- */
-/*
- * Base styles.
- *
- * Themes should include this file after defining their variables and mixins.
- */
-/* @noflip */
-.oo-ui-rtl {
- direction: rtl;
-}
-/* @noflip */
-.oo-ui-ltr {
- direction: ltr;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button {
- 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-buttonElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- display: none;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- display: none;
-}
-.oo-ui-buttonElement.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
- cursor: default;
-}
-.oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
-.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-buttonElement-frameless {
- display: inline-block;
- position: relative;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
- display: inline-block;
- vertical-align: top;
- text-align: center;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- cursor: default;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-left: 0;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- margin-right: -0.75em;
-}
-.oo-ui-buttonElement.oo-ui-indicatorElement .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
-.oo-ui-buttonElement.oo-ui-iconElement .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- width: 3.35em;
- height: 3.35em;
- background-size: 2em auto;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- margin-left: 0.25em;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- line-height: 1.9em;
-}
-.oo-ui-clippableElement-clippable {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
- overflow-y: hidden;
-}
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
- 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-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;
-}
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
- padding: 0 0 1em;
-}
-.oo-ui-fieldLayout {
- margin-bottom: 1em;
-}
-.oo-ui-fieldLayout:before,
-.oo-ui-fieldLayout:after {
- content: " ";
- display: table;
-}
-.oo-ui-fieldLayout:after {
- clear: both;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- display: block;
- float: left;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
- display: block;
- float: left;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- text-align: right;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
- display: inline-block;
-}
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
- z-index: 1;
-}
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help {
- float: right;
-}
-.oo-ui-fieldLayout .oo-ui-fieldLayout-help-content {
- padding: 0.5em 0.75em;
-}
-.oo-ui-fieldLayout:last-child {
- margin-bottom: 0;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- padding-top: 0.5em;
- margin-right: 5%;
- width: 35%;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
- width: 60%;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
- padding: 0.75em 0.5em 0.5em 0.5em;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
- padding: 0.5em 0;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
- padding: 0.5em 0;
-}
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-top: 0.25em;
-}
-.oo-ui-fieldLayout-disabled .oo-ui-labelElement-label {
- color: #cccccc;
-}
-.oo-ui-fieldsetLayout {
- position: relative;
- margin: 0;
- padding: 0;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
- display: block;
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-fieldsetLayout.oo-ui-labelElement > .oo-ui-labelElement-label {
- display: inline-block;
-}
-.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout {
- margin-top: 2em;
-}
-.oo-ui-fieldsetLayout > .oo-ui-labelElement-label {
- margin-bottom: 0.5em;
- padding: 0.25em 0;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-labelElement-label {
- padding-left: 1.75em;
- line-height: 1.33em;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
- left: 0;
- top: 0.25em;
- width: 2em;
- height: 2em;
-}
-.oo-ui-gridLayout {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
-}
-.oo-ui-panelLayout {
- position: relative;
- padding: 1em 3.35em;
-}
-.oo-ui-panelLayout-scrollable {
- overflow-y: auto;
-}
-.oo-ui-panelLayout-expanded {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
-}
-.oo-ui-stackLayout > .oo-ui-panelLayout {
- display: none;
-}
-.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
- display: block;
- position: relative;
-}
-.oo-ui-popupTool .oo-ui-popupWidget-popup,
-.oo-ui-popupTool .oo-ui-popupWidget-anchor {
- z-index: 4;
-}
-.oo-ui-popupTool .oo-ui-popupWidget {
- margin-left: 1.25em;
- font-size: 0.8em;
-}
-.oo-ui-toolGroup {
- display: inline-block;
- vertical-align: middle;
- margin: 0.3em;
-}
-.oo-ui-toolGroup-empty {
- display: none;
-}
-.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-barToolGroup > .oo-ui-iconElement-icon,
-.oo-ui-barToolGroup > .oo-ui-labelElement-label {
- display: none;
-}
-.oo-ui-barToolGroup .oo-ui-tool {
- display: inline-block;
- position: relative;
- vertical-align: top;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link {
- display: block;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- display: block;
-}
-.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-title,
-.oo-ui-barToolGroup .oo-ui-tool-accel {
- display: none;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-link {
- cursor: pointer;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link {
- height: 1.5em;
- padding: 0.25em;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- height: 1.5em;
- width: 1.5em;
-}
-.oo-ui-popupToolGroup {
- position: relative;
- height: 2em;
- min-width: 2.5em;
-}
-.oo-ui-popupToolGroup-handle {
- display: block;
- cursor: pointer;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-popupToolGroup.oo-ui-widget-disabled .oo-ui-popupToolGroup-handle {
- cursor: default;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
- display: none;
- position: absolute;
- z-index: 4;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconElement-icon {
- background-repeat: no-repeat;
- background-position: center center;
-}
-.oo-ui-popupToolGroup-active.oo-ui-widget-enabled > .oo-ui-toolGroup-tools {
- display: block;
-}
-.oo-ui-popupToolGroup-left > .oo-ui-toolGroup-tools {
- left: 0;
-}
-.oo-ui-popupToolGroup-right > .oo-ui-toolGroup-tools {
- right: 0;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-accel {
- display: none;
-}
-.oo-ui-popupToolGroup.oo-ui-indicatorElement.oo-ui-iconElement {
- min-width: 3.5em;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- top: 0;
- width: 2em;
- height: 2em;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
- right: 0;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- left: 0.25em;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- line-height: 2.6em;
- font-size: 0.8em;
- margin: 0 1em;
-}
-.oo-ui-popupToolGroup-header {
- line-height: 2.6em;
- font-size: 0.8em;
- margin: 0 0.6em;
- font-weight: bold;
-}
-.oo-ui-popupToolGroup.oo-ui-iconElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-left: 3em;
-}
-.oo-ui-popupToolGroup.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-right: 2.25em;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
- top: 2.3em;
- margin: 0 -1px;
- border: solid 1px #dddddd;
- background-color: white;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- height: 2em;
- width: 2em;
- margin-right: 0.25em;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
- line-height: 2em;
- font-size: 0.8em;
-}
-.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;
-}
-.oo-ui-listToolGroup .oo-ui-tool-link {
- display: block;
- cursor: pointer;
- white-space: nowrap;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
-.oo-ui-listToolGroup .oo-ui-toolGroup-tools {
- padding: 0.25em;
-}
-.oo-ui-listToolGroup .oo-ui-tool-link {
- padding-right: 0.5em;
-}
-.oo-ui-menuToolGroup .oo-ui-tool {
- display: block;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-link {
- display: block;
- cursor: pointer;
- white-space: nowrap;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-image: none;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-image: /* @embed */ url(images/icons/check.svg);
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
-.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
- min-width: 8em;
-}
-.oo-ui-menuToolGroup .oo-ui-toolGroup-tools {
- padding: 0.25em 0 0.25em 0;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-link {
- padding: 0 1em 0 0.25em;
-}
-.oo-ui-toolbar {
- clear: both;
-}
-.oo-ui-toolbar-bar {
- line-height: 1em;
-}
-.oo-ui-toolbar-actions {
- float: right;
-}
-.oo-ui-toolbar-tools {
- display: inline;
-}
-.oo-ui-toolbar-tools,
-.oo-ui-toolbar-actions,
-.oo-ui-toolbar-shadow {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-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 {
- background-position: left top;
- background-repeat: repeat-x;
- position: absolute;
- width: 100%;
- pointer-events: none;
-}
-.oo-ui-toolbar-bar {
- border-bottom: solid 1px #dddddd;
- background: white;
-}
-.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
- border: none;
- background: none;
-}
-.oo-ui-selectWidget {
- margin: 0;
- padding: 0;
-}
-.oo-ui-optionWidget {
- position: relative;
- display: block;
- cursor: pointer;
- padding: 0.8em 1em 0.8em 3.35em;
- border: none;
- font-weight: bold;
-}
-.oo-ui-optionWidget.oo-ui-widget-disabled {
- cursor: default;
-}
-.oo-ui-optionWidget .oo-ui-labelElement-label {
- display: block;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
-}
-.oo-ui-optionWidget .oo-ui-labelElement-label {
- line-height: 1.5em;
-}
-.oo-ui-optionWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
- padding-right: 1.5em;
-}
-.oo-ui-optionWidget-level-0 {
- padding-left: 3.5em;
-}
-.oo-ui-optionWidget-level-0 .oo-ui-iconElement-icon {
- left: 1em;
-}
-.oo-ui-optionWidget-level-1 {
- padding-left: 5em;
-}
-.oo-ui-optionWidget-level-1 .oo-ui-iconElement-icon {
- left: 2.5em;
-}
-.oo-ui-optionWidget-level-2 {
- padding-left: 6.5em;
-}
-.oo-ui-optionWidget-level-2 .oo-ui-iconElement-icon {
- left: 4em;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon,
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- position: absolute;
- background-repeat: no-repeat;
- background-position: center center;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon,
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- top: 50%;
- width: 2em;
- height: 2em;
- margin-top: -1em;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon {
- left: 0.5em;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- right: 0.5em;
-}
-.oo-ui-buttonSelectWidget {
- display: inline-block;
- white-space: nowrap;
-}
-.oo-ui-buttonOptionWidget {
- display: inline-block;
- padding: 0;
- background-color: transparent;
-}
-.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- position: relative;
-}
-.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
-.oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- position: static;
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- height: 1.9em;
-}
-.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
-.oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- height: 1.9em;
- margin-top: 0;
-}
-.oo-ui-labelWidget {
- display: inline-block;
- padding: 0.5em 0;
-}
-.oo-ui-iconWidget {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- line-height: 2.5em;
- height: 1.9em;
- width: 1.9em;
- opacity: 0.8;
-}
-.oo-ui-iconWidget.oo-ui-widget-disabled {
- opacity: 0.2;
-}
-.oo-ui-indicatorWidget {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- line-height: 2.5em;
- height: 1.9em;
- width: 1.9em;
- opacity: 0.8;
-}
-.oo-ui-indicatorWidget.oo-ui-widget-disabled {
- opacity: 0.2;
-}
-.oo-ui-buttonWidget {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonGroupWidget {
- border-radius: 0.3em;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-bottom: -1px;
- margin-left: -1px;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:first-child .oo-ui-buttonElement-button {
- border-bottom-left-radius: 0.3em;
- border-top-left-radius: 0.3em;
- margin-left: 0;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:last-child .oo-ui-buttonElement-button {
- border-bottom-right-radius: 0.3em;
- border-top-right-radius: 0.3em;
-}
-.oo-ui-toggleSwitchWidget {
- position: relative;
- display: inline-block;
- vertical-align: middle;
- overflow: hidden;
- 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);
- height: 2em;
- width: 4em;
-}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
- cursor: default;
-}
-.oo-ui-toggleSwitchWidget-grip {
- position: absolute;
- display: block;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
- position: absolute;
- top: 0;
- bottom: 0;
- right: 0;
- left: 0;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
- display: none;
-}
-.oo-ui-toggleSwitchWidget-grip {
- top: 0.25em;
- left: 0.25em;
- width: 1.5em;
- height: 1.5em;
- margin-top: -1px;
- -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;
- -ms-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 .oo-ui-toggleSwitchWidget-glow {
- -webkit-transition: opacity 200ms ease-in-out;
- -moz-transition: opacity 200ms ease-in-out;
- -ms-transition: opacity 200ms ease-in-out;
- -o-transition: opacity 200ms ease-in-out;
- transition: opacity 200ms ease-in-out;
-}
-.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
- left: 2.25em;
- margin-left: -2px;
-}
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
- left: 0.25em;
- margin-left: 0;
-}
-.oo-ui-actionWidget.oo-ui-pendingElement-pending {
- background-image: /* @embed */ url(images/textures/pending.gif);
-}
-.oo-ui-popupWidget-popup {
- position: absolute;
- overflow: hidden;
- z-index: 1;
-}
-.oo-ui-popupWidget-anchor {
- display: none;
- z-index: 1;
-}
-.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
- display: block;
- position: absolute;
- background-repeat: no-repeat;
-}
-.oo-ui-popupWidget-head {
- -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;
-}
-.oo-ui-popupWidget-head .oo-ui-labelElement-label {
- float: left;
- cursor: default;
-}
-.oo-ui-popupWidget-body {
- clear: both;
- overflow: hidden;
-}
-.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
- margin-top: 7px;
-}
-.oo-ui-popupWidget-head {
- height: 2.5em;
-}
-.oo-ui-popupWidget-head .oo-ui-buttonWidget {
- margin: 0.25em;
-}
-.oo-ui-popupWidget-head .oo-ui-labelElement-label {
- margin: 0.75em 1em;
-}
-.oo-ui-popupWidget-body-padded {
- padding: 0 1em;
-}
-.oo-ui-popupButtonWidget {
- position: relative;
-}
-.oo-ui-popupButtonWidget .oo-ui-popupWidget {
- position: absolute;
- left: 1em;
- cursor: auto;
-}
-.oo-ui-lookupInputWidget-menu {
- background-color: #ffffff;
-}
-.oo-ui-textInputWidget {
- position: relative;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-textInputWidget input,
-.oo-ui-textInputWidget textarea {
- display: inline-block;
- width: 100%;
- resize: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-textInputWidget.oo-ui-pendingElement-pending input,
-.oo-ui-textInputWidget.oo-ui-pendingElement-pending textarea {
- background-image: /* @embed */ url(images/textures/pending.gif);
-}
-.oo-ui-textInputWidget > .oo-ui-iconElement-icon,
-.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator {
- position: absolute;
- top: 0;
- height: 100%;
- background-repeat: no-repeat;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-textInputWidget > .oo-ui-iconElement-icon {
- left: 0;
-}
-.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator {
- right: 0;
-}
-.oo-ui-textInputWidget input,
-.oo-ui-textInputWidget textarea {
- padding: 0.8em 1em;
-}
-.oo-ui-menuWidget {
- position: absolute;
- background: white;
- border: solid 1px #dddddd;
-}
-.oo-ui-menuWidget input {
- position: absolute;
- width: 0;
- height: 0;
- overflow: hidden;
- opacity: 0;
-}
-.oo-ui-menuItemWidget {
- position: relative;
-}
-.oo-ui-menuItemWidget .oo-ui-iconElement-icon {
- display: none;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
- background-color: transparent;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected .oo-ui-iconElement-icon {
- display: block;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
- background: #347bff;
- color: #ffffff;
-}
-.oo-ui-menuItemWidget .oo-ui-iconElement-icon {
- background-size: 24px auto;
-}
-.oo-ui-menuSectionItemWidget {
- cursor: default;
- font-weight: normal;
- color: #777777;
- border: none;
-}
-.oo-ui-inlineMenuWidget {
- position: relative;
- display: inline-block;
- margin: 0.25em 0;
- min-width: 20em;
-}
-.oo-ui-inlineMenuWidget-handle {
- width: 100%;
- display: inline-block;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-inlineMenuWidget .oo-ui-menuWidget {
- z-index: 1;
- width: 100%;
-}
-.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-inlineMenuWidget-handle {
- cursor: default;
-}
-.oo-ui-inlineMenuWidget-handle {
- height: 2.5em;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- top: 0;
- width: 2.5em;
- height: 2.5em;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator {
- right: 0;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- left: 0.25em;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- line-height: 2.5em;
- margin: 0 0.5em;
-}
-.oo-ui-inlineMenuWidget.oo-ui-iconElement .oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- margin-left: 3em;
-}
-.oo-ui-inlineMenuWidget.oo-ui-indicatorElement .oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- margin-right: 2em;
-}
-.oo-ui-outlineItemWidget {
- position: relative;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- padding: 0.75em;
-}
-.oo-ui-outlineControlsWidget {
- height: 3em;
-}
-.oo-ui-outlineControlsWidget-items,
-.oo-ui-outlineControlsWidget-movers {
- float: left;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
- float: left;
- background-position: right center;
- background-repeat: no-repeat;
-}
-.oo-ui-outlineControlsWidget-items {
- float: left;
-}
-.oo-ui-outlineControlsWidget-items .oo-ui-buttonWidget {
- float: left;
-}
-.oo-ui-outlineControlsWidget-movers {
- float: right;
-}
-.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
- float: right;
-}
-.oo-ui-outlineControlsWidget-items,
-.oo-ui-outlineControlsWidget-movers {
- height: 2em;
- margin: 0.5em;
- padding: 0;
-}
-.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
- width: 1.5em;
- height: 2em;
- margin: 0.5em 0 0.5em 0.5em;
-}
-.oo-ui-outlineControlsWidget-items {
- margin-left: 0;
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget {
- z-index: 1;
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget > .oo-ui-selectWidget {
- min-width: 20em;
-}
-.oo-ui-searchWidget-query {
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
-}
-.oo-ui-searchWidget-query .oo-ui-textInputWidget {
- width: 100%;
-}
-.oo-ui-searchWidget-results {
- position: absolute;
- bottom: 0;
- left: 0;
- right: 0;
- overflow-x: hidden;
- overflow-y: auto;
-}
-.oo-ui-searchWidget-query {
- height: 4em;
- padding: 0 1em;
-}
-.oo-ui-searchWidget-query .oo-ui-textInputWidget {
- margin: 0.75em 0;
-}
-.oo-ui-searchWidget-results {
- top: 4em;
- padding: 1em;
- line-height: 0;
-}
-.oo-ui-window {
- line-height: 1em;
- /* Content div takes focus when opened, so hide outline */
-}
-.oo-ui-window-frame {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-window-frame > iframe {
- width: 100%;
- height: 100%;
- margin: 0;
- padding: 0;
-}
-.oo-ui-window-content:focus {
- outline: none;
-}
-.oo-ui-window-head,
-.oo-ui-window-foot {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-window-body {
- margin: 0;
- padding: 0;
- background: none;
-}
-.oo-ui-window-overlay {
- position: absolute;
- top: 0;
- left: 0;
-}
-.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;
- overflow: hidden;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-dialog-content > .oo-ui-window-head {
- z-index: 1;
- top: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-head.oo-ui-pendingElement-pending {
- background-image: /* @embed */ url(images/textures/pending.gif);
-}
-.oo-ui-dialog-content > .oo-ui-window-body {
- z-index: 2;
- top: 0;
- bottom: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-foot {
- z-index: 1;
- bottom: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-overlay {
- z-index: 3;
-}
-.oo-ui-messageDialog-actions-horizontal {
- display: table;
- table-layout: fixed;
- width: 100%;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
- display: table-cell;
- width: 1%;
-}
-.oo-ui-messageDialog-actions-vertical {
- display: block;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget {
- position: relative;
- text-align: center;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-buttonElement-button {
- display: block;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labelElement-label {
- position: relative;
- top: auto;
- bottom: auto;
- display: inline;
- white-space: nowrap;
-}
-.oo-ui-messageDialog-title,
-.oo-ui-messageDialog-message {
- display: block;
- text-align: center;
- padding-top: 0.5em;
-}
-.oo-ui-messageDialog-title {
- font-size: 1.5em;
- line-height: 1em;
- color: #000000;
-}
-.oo-ui-messageDialog-message {
- font-size: 0.9em;
- line-height: 1.25em;
- color: #666666;
-}
-.oo-ui-messageDialog-message-verbose {
- font-size: 1.1em;
- line-height: 1.5em;
- text-align: left;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
- border-right: solid 1px #e5e5e5;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
- border-right-width: 0;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
- border-bottom: solid 1px #e5e5e5;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
- border-bottom-width: 0;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labelElement-label {
- text-align: center;
- line-height: 3.4em;
- padding: 0 2em;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget:hover {
- background-color: rgba(0, 0, 0, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
- background-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
- background-color: rgba(8, 126, 204, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
- background-color: rgba(8, 126, 204, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
- font-weight: bold;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
- background-color: rgba(118, 171, 54, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active {
- background-color: rgba(118, 171, 54, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover {
- background-color: rgba(212, 83, 83, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active {
- background-color: rgba(212, 83, 83, 0.1);
-}
-.oo-ui-processDialog-location {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.oo-ui-processDialog-title {
- display: inline;
- padding: 0;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget {
- white-space: nowrap;
-}
-.oo-ui-processDialog-actions-safe,
-.oo-ui-processDialog-actions-primary {
- position: absolute;
- top: 0;
- bottom: 0;
-}
-.oo-ui-processDialog-actions-safe {
- left: 0;
-}
-.oo-ui-processDialog-actions-primary {
- right: 0;
-}
-.oo-ui-processDialog-errors {
- display: none;
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- z-index: 2;
- overflow-x: hidden;
- overflow-y: auto;
-}
-.oo-ui-processDialog-content .oo-ui-window-head {
- height: 3.35em;
- border-bottom: 1px solid #dddddd;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-processDialog-content .oo-ui-window-body {
- top: 3.35em;
- padding: 2em 0;
-}
-.oo-ui-processDialog-navigation {
- position: relative;
- height: 3.35em;
- padding: 0 1em;
-}
-.oo-ui-processDialog-location {
- padding: 0.75em 0;
- height: 1.85em;
- cursor: default;
- text-align: center;
-}
-.oo-ui-processDialog-title {
- font-weight: bold;
- line-height: 1.85em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-buttonElement-button {
- padding: 0.35em 0.75em;
- min-width: 1.85em;
- min-height: 1.85em;
- border: 1px solid #dddddd;
- border-radius: 4px;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-labelElement-label {
- line-height: 1.85em;
- padding: 0 1em;
- font-weight: bold;
- color: #777777;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-iconElement-icon,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-iconElement-icon,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-iconElement-icon {
- position: absolute;
- margin-top: -0.125em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
- vertical-align: middle;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-buttonElement-button {
- border: 1px solid transparent;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-labelElement-label {
- color: #d11d13;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonElement-button {
- padding: 0.75em 0.35em;
- border: none;
- border-radius: 0;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-buttonElement-button {
- background-color: #347bff;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
- color: #ffffff;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- left: 0.5em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-labelElement-label {
- padding-left: 2.25em;
-}
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- right: 0.5em;
-}
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-labelElement-label {
- padding-right: 2.25em;
-}
-.oo-ui-processDialog-actions-other {
- position: absolute;
- bottom: 1em;
-}
-.oo-ui-processDialog > .oo-ui-window-frame {
- min-height: 5em;
-}
-.oo-ui-processDialog-errors {
- background-color: rgba(255, 255, 255, 0.9);
- padding: 3em 3em 1.5em 3em;
- text-align: center;
-}
-.oo-ui-processDialog-errors .oo-ui-buttonWidget {
- margin: 2em 1em 2em 1em;
-}
-.oo-ui-processDialog-errors-title {
- font-size: 1.5em;
- color: #000000;
- margin-bottom: 2em;
-}
-.oo-ui-processDialog-error {
- text-align: left;
- margin: 1em;
- padding: 1em;
- border: solid 1px #ff9e9e;
- background-color: #fff7f7;
- border-radius: 0.25em;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog {
- position: fixed;
- width: 0;
- height: 0;
- overflow: hidden;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup {
- width: auto;
- height: auto;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- padding: 1em;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame {
- position: absolute;
- right: 0;
- left: 0;
- margin: auto;
- overflow: hidden;
- max-width: 100%;
- max-height: 100%;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame > iframe {
- width: 100%;
- height: 100%;
-}
-.oo-ui-windowManager-fullscreen > .oo-ui-dialog > .oo-ui-window-frame {
- width: 100%;
- height: 100%;
- top: 0;
- bottom: 0;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog {
- background-color: rgba(255, 255, 255, 0.5);
- opacity: 0;
- -webkit-transition: opacity 250ms ease-in-out;
- -moz-transition: opacity 250ms ease-in-out;
- -ms-transition: opacity 250ms ease-in-out;
- -o-transition: opacity 250ms ease-in-out;
- transition: opacity 250ms ease-in-out;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
- top: 0;
- bottom: 0;
- background-color: #ffffff;
- -webkit-transform: translate3d(0, -200%, 0);
- -moz-transform: translate3d(0, -200%, 0);
- -ms-transform: translate3d(0, -200%, 0);
- -o-transform: translate3d(0, -200%, 0);
- transform: translate3d(0, -200%, 0);
- -webkit-transition: transform 250ms ease-in-out;
- -moz-transition: transform 250ms ease-in-out;
- -ms-transition: transform 250ms ease-in-out;
- -o-transition: transform 250ms ease-in-out;
- transition: transform 250ms ease-in-out;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
- opacity: 1;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
- -webkit-transform: translate3d(0, 0, 0);
- -moz-transform: translate3d(0, 0, 0);
- -ms-transform: translate3d(0, 0, 0);
- -o-transform: translate3d(0, 0, 0);
- transform: translate3d(0, 0, 0);
-}
-.oo-ui-windowManager-modal.oo-ui-windowManager-floating > .oo-ui-dialog > .oo-ui-window-frame {
- border: solid 1px #cccccc;
- border-radius: 0.5em;
- box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
-}
-
-/*
- * Blank theme mixins.
- *
- * Base styles invoke these mixins at the end of their definitions. Override these mixins to add
- * additional rules to the base styles.
- */
-.oo-ui-icon-check {
- background-image: /* @embed */ url(themes/minerva/images/icons/check.png);
- background: #347bff;
-}
diff --git a/resources/lib/oojs-ui/oojs-ui-minerva.rtl.css b/resources/lib/oojs-ui/oojs-ui-minerva.rtl.css
deleted file mode 100644
index e452952a..00000000
--- a/resources/lib/oojs-ui/oojs-ui-minerva.rtl.css
+++ /dev/null
@@ -1,1381 +0,0 @@
-/*!
- * OOjs UI v0.1.0
- * 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: 2014-09-11T19:39:50Z
- */
-/*
- * Blank theme mixins.
- *
- * Base styles invoke these mixins at the end of their definitions. Override these mixins to add
- * additional rules to the base styles.
- */
-/*
- * Base styles.
- *
- * Themes should include this file after defining their variables and mixins.
- */
-/* @noflip */
-.oo-ui-rtl {
- direction: rtl;
-}
-/* @noflip */
-.oo-ui-ltr {
- direction: ltr;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button {
- 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-buttonElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- display: none;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- display: none;
-}
-.oo-ui-buttonElement.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
- cursor: default;
-}
-.oo-ui-buttonElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
-.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-buttonElement-frameless {
- display: inline-block;
- position: relative;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
- display: inline-block;
- vertical-align: top;
- text-align: center;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
-.oo-ui-buttonElement-framed.oo-ui-widget-disabled.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
- cursor: default;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-right: 0;
-}
-.oo-ui-buttonElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
- margin-left: -0.75em;
-}
-.oo-ui-buttonElement.oo-ui-indicatorElement .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator,
-.oo-ui-buttonElement.oo-ui-iconElement .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- width: 3.35em;
- height: 3.35em;
- background-size: 2em auto;
-}
-.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- margin-right: 0.25em;
-}
-.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- line-height: 1.9em;
-}
-.oo-ui-clippableElement-clippable {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
- overflow-y: hidden;
-}
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
- 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-editable .oo-ui-outlineWidget {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- bottom: 3em;
- overflow-y: auto;
-}
-.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
- position: absolute;
- bottom: 0;
- right: 0;
- left: 0;
-}
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
- padding: 0 0 1em;
-}
-.oo-ui-fieldLayout {
- margin-bottom: 1em;
-}
-.oo-ui-fieldLayout:before,
-.oo-ui-fieldLayout:after {
- content: " ";
- display: table;
-}
-.oo-ui-fieldLayout:after {
- clear: both;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- display: block;
- float: right;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
- display: block;
- float: right;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- text-align: left;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
- display: inline-block;
-}
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-popupWidget > .oo-ui-popupWidget-popup {
- z-index: 1;
-}
-.oo-ui-fieldLayout:last-child {
- margin-bottom: 0;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labelElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labelElement-label {
- padding-top: 0.5em;
- margin-left: 5%;
- width: 35%;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
- width: 60%;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labelElement-label {
- padding: 0.75em 0.5em 0.5em 0.5em;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
- padding: 0.5em 0;
-}
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labelElement-label {
- padding: 0.5em 0;
-}
-.oo-ui-fieldLayout > .oo-ui-popupButtonWidget > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-top: 0.25em;
-}
-.oo-ui-fieldLayout-disabled .oo-ui-labelElement-label {
- color: #ccc;
-}
-.oo-ui-fieldsetLayout {
- position: relative;
- margin: 0;
- padding: 0;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
- display: block;
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-fieldsetLayout.oo-ui-labelElement > .oo-ui-labelElement-label {
- display: inline-block;
-}
-.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout {
- margin-top: 2em;
-}
-.oo-ui-fieldsetLayout > .oo-ui-labelElement-label {
- margin-bottom: 0.5em;
- padding: 0.25em 0;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-labelElement-label {
- padding-right: 1.75em;
- line-height: 1.33em;
-}
-.oo-ui-fieldsetLayout.oo-ui-iconElement > .oo-ui-iconElement-icon {
- right: 0;
- top: 0.25em;
- width: 2em;
- height: 2em;
-}
-.oo-ui-gridLayout {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- bottom: 0;
-}
-.oo-ui-panelLayout {
- position: relative;
- padding: 1em 3.35em;
-}
-.oo-ui-panelLayout-scrollable {
- overflow-y: auto;
-}
-.oo-ui-panelLayout-expanded {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- bottom: 0;
-}
-.oo-ui-stackLayout > .oo-ui-panelLayout {
- display: none;
-}
-.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
- display: block;
- position: relative;
-}
-.oo-ui-popupTool .oo-ui-popupWidget-popup,
-.oo-ui-popupTool .oo-ui-popupWidget-anchor {
- z-index: 4;
-}
-.oo-ui-popupTool .oo-ui-popupWidget {
- margin-right: 1.25em;
- font-size: 0.8em;
-}
-.oo-ui-toolGroup {
- display: inline-block;
- vertical-align: middle;
- margin: 0.3em;
-}
-.oo-ui-toolGroup-empty {
- display: none;
-}
-.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-barToolGroup > .oo-ui-iconElement-icon,
-.oo-ui-barToolGroup > .oo-ui-labelElement-label {
- display: none;
-}
-.oo-ui-barToolGroup .oo-ui-tool {
- display: inline-block;
- position: relative;
- vertical-align: top;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link {
- display: block;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- display: block;
-}
-.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-title,
-.oo-ui-barToolGroup .oo-ui-tool-accel {
- display: none;
-}
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-link {
- cursor: pointer;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link {
- height: 1.5em;
- padding: 0.25em;
-}
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- height: 1.5em;
- width: 1.5em;
-}
-.oo-ui-popupToolGroup {
- position: relative;
- height: 2em;
- min-width: 2.5em;
-}
-.oo-ui-popupToolGroup-handle {
- display: block;
- cursor: pointer;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-popupToolGroup.oo-ui-widget-disabled .oo-ui-popupToolGroup-handle {
- cursor: default;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
- display: none;
- position: absolute;
- z-index: 4;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconElement-icon {
- background-repeat: no-repeat;
- background-position: center center;
-}
-.oo-ui-popupToolGroup-active.oo-ui-widget-enabled > .oo-ui-toolGroup-tools {
- display: block;
-}
-.oo-ui-popupToolGroup-left > .oo-ui-toolGroup-tools {
- right: 0;
-}
-.oo-ui-popupToolGroup-right > .oo-ui-toolGroup-tools {
- left: 0;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-accel {
- display: none;
-}
-.oo-ui-popupToolGroup.oo-ui-indicatorElement.oo-ui-iconElement {
- min-width: 3.5em;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- top: 0;
- width: 2em;
- height: 2em;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-indicatorElement-indicator {
- left: 0;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
- right: 0.25em;
-}
-.oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- line-height: 2.6em;
- font-size: 0.8em;
- margin: 0 1em;
-}
-.oo-ui-popupToolGroup-header {
- line-height: 2.6em;
- font-size: 0.8em;
- margin: 0 0.6em;
- font-weight: bold;
-}
-.oo-ui-popupToolGroup.oo-ui-iconElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-right: 3em;
-}
-.oo-ui-popupToolGroup.oo-ui-indicatorElement .oo-ui-popupToolGroup-handle .oo-ui-labelElement-label {
- margin-left: 2.25em;
-}
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
- top: 2.3em;
- margin: 0 -1px;
- border: solid 1px #dddddd;
- background-color: white;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- height: 2em;
- width: 2em;
- margin-left: 0.25em;
-}
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
- line-height: 2em;
- font-size: 0.8em;
-}
-.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;
-}
-.oo-ui-listToolGroup .oo-ui-tool-link {
- display: block;
- cursor: pointer;
- white-space: nowrap;
-}
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
-.oo-ui-listToolGroup .oo-ui-toolGroup-tools {
- padding: 0.25em;
-}
-.oo-ui-listToolGroup .oo-ui-tool-link {
- padding-left: 0.5em;
-}
-.oo-ui-menuToolGroup .oo-ui-tool {
- display: block;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-link {
- display: block;
- cursor: pointer;
- white-space: nowrap;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-image: none;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-active .oo-ui-tool-link .oo-ui-iconElement-icon {
- background-image: /* @embed */ url(images/icons/check.svg);
-}
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
-.oo-ui-menuToolGroup .oo-ui-popupToolGroup-handle {
- min-width: 8em;
-}
-.oo-ui-menuToolGroup .oo-ui-toolGroup-tools {
- padding: 0.25em 0 0.25em 0;
-}
-.oo-ui-menuToolGroup .oo-ui-tool-link {
- padding: 0 0.25em 0 1em;
-}
-.oo-ui-toolbar {
- clear: both;
-}
-.oo-ui-toolbar-bar {
- line-height: 1em;
-}
-.oo-ui-toolbar-actions {
- float: left;
-}
-.oo-ui-toolbar-tools {
- display: inline;
-}
-.oo-ui-toolbar-tools,
-.oo-ui-toolbar-actions,
-.oo-ui-toolbar-shadow {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-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 {
- background-position: right top;
- background-repeat: repeat-x;
- position: absolute;
- width: 100%;
- pointer-events: none;
-}
-.oo-ui-toolbar-bar {
- border-bottom: solid 1px #dddddd;
- background: white;
-}
-.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
- border: none;
- background: none;
-}
-.oo-ui-selectWidget {
- margin: 0;
- padding: 0;
-}
-.oo-ui-optionWidget {
- position: relative;
- display: block;
- cursor: pointer;
- padding: 0.8em 3.35em 0.8em 1em;
- border: none;
- font-weight: bold;
-}
-.oo-ui-optionWidget.oo-ui-widget-disabled {
- cursor: default;
-}
-.oo-ui-optionWidget .oo-ui-labelElement-label {
- display: block;
- white-space: nowrap;
- text-overflow: ellipsis;
- overflow: hidden;
-}
-.oo-ui-optionWidget .oo-ui-labelElement-label {
- line-height: 1.5em;
-}
-.oo-ui-optionWidget.oo-ui-indicatorElement .oo-ui-labelElement-label {
- padding-left: 1.5em;
-}
-.oo-ui-optionWidget-level-0 {
- padding-right: 3.5em;
-}
-.oo-ui-optionWidget-level-0 .oo-ui-iconElement-icon {
- right: 1em;
-}
-.oo-ui-optionWidget-level-1 {
- padding-right: 5em;
-}
-.oo-ui-optionWidget-level-1 .oo-ui-iconElement-icon {
- right: 2.5em;
-}
-.oo-ui-optionWidget-level-2 {
- padding-right: 6.5em;
-}
-.oo-ui-optionWidget-level-2 .oo-ui-iconElement-icon {
- right: 4em;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon,
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- position: absolute;
- background-repeat: no-repeat;
- background-position: center center;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon,
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- top: 50%;
- width: 2em;
- height: 2em;
- margin-top: -1em;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-iconElement-icon {
- right: 0.5em;
-}
-.oo-ui-decoratedOptionWidget .oo-ui-indicatorElement-indicator {
- left: 0.5em;
-}
-.oo-ui-buttonSelectWidget {
- display: inline-block;
- white-space: nowrap;
-}
-.oo-ui-buttonOptionWidget {
- display: inline-block;
- padding: 0;
- background-color: transparent;
-}
-.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- position: relative;
-}
-.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
-.oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- position: static;
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonOptionWidget .oo-ui-buttonElement-button {
- height: 1.9em;
-}
-.oo-ui-buttonOptionWidget.oo-ui-iconElement .oo-ui-iconElement-icon,
-.oo-ui-buttonOptionWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
- height: 1.9em;
- margin-top: 0;
-}
-.oo-ui-labelWidget {
- display: inline-block;
- padding: 0.5em 0;
-}
-.oo-ui-iconWidget {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- line-height: 2.5em;
- height: 1.9em;
- width: 1.9em;
- opacity: 0.8;
-}
-.oo-ui-iconWidget.oo-ui-widget-disabled {
- opacity: 0.2;
-}
-.oo-ui-indicatorWidget {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- line-height: 2.5em;
- height: 1.9em;
- width: 1.9em;
- opacity: 0.8;
-}
-.oo-ui-indicatorWidget.oo-ui-widget-disabled {
- opacity: 0.2;
-}
-.oo-ui-buttonWidget {
- display: inline-block;
- vertical-align: middle;
-}
-.oo-ui-buttonGroupWidget {
- border-radius: 0.3em;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
- border-radius: 0;
- margin-bottom: -1px;
- margin-right: -1px;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:first-child .oo-ui-buttonElement-button {
- border-bottom-right-radius: 0.3em;
- border-top-right-radius: 0.3em;
- margin-right: 0;
-}
-.oo-ui-buttonGroupWidget .oo-ui-buttonElement-framed:last-child .oo-ui-buttonElement-button {
- border-bottom-left-radius: 0.3em;
- border-top-left-radius: 0.3em;
-}
-.oo-ui-toggleSwitchWidget {
- position: relative;
- display: inline-block;
- vertical-align: middle;
- overflow: hidden;
- 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);
- height: 2em;
- width: 4em;
-}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
- cursor: default;
-}
-.oo-ui-toggleSwitchWidget-grip {
- position: absolute;
- display: block;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
- position: absolute;
- top: 0;
- bottom: 0;
- left: 0;
- right: 0;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
- display: none;
-}
-.oo-ui-toggleSwitchWidget-grip {
- top: 0.25em;
- right: 0.25em;
- width: 1.5em;
- height: 1.5em;
- margin-top: -1px;
- -webkit-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
- -moz-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
- -ms-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
- -o-transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
- transition: right 200ms ease-in-out, margin-right 200ms ease-in-out;
-}
-.oo-ui-toggleSwitchWidget .oo-ui-toggleSwitchWidget-glow {
- -webkit-transition: opacity 200ms ease-in-out;
- -moz-transition: opacity 200ms ease-in-out;
- -ms-transition: opacity 200ms ease-in-out;
- -o-transition: opacity 200ms ease-in-out;
- transition: opacity 200ms ease-in-out;
-}
-.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
- right: 2.25em;
- margin-right: -2px;
-}
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
- right: 0.25em;
- margin-right: 0;
-}
-.oo-ui-popupWidget-popup {
- position: absolute;
- overflow: hidden;
- z-index: 1;
-}
-.oo-ui-popupWidget-anchor {
- display: none;
- z-index: 1;
-}
-.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor {
- display: block;
- position: absolute;
- background-repeat: no-repeat;
-}
-.oo-ui-popupWidget-head {
- -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: left;
-}
-.oo-ui-popupWidget-head .oo-ui-labelElement-label {
- float: right;
- cursor: default;
-}
-.oo-ui-popupWidget-body {
- clear: both;
- overflow: hidden;
-}
-.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
- margin-top: 7px;
-}
-.oo-ui-popupWidget-head {
- height: 2.5em;
-}
-.oo-ui-popupWidget-head .oo-ui-buttonWidget {
- margin: 0.25em;
-}
-.oo-ui-popupWidget-head .oo-ui-labelElement-label {
- margin: 0.75em 1em;
-}
-.oo-ui-popupWidget-body-padded {
- padding: 0 1em;
-}
-.oo-ui-popupButtonWidget {
- position: relative;
-}
-.oo-ui-popupButtonWidget .oo-ui-popupWidget {
- position: absolute;
- right: 1em;
- cursor: auto;
-}
-.oo-ui-lookupInputWidget-menu {
- background-color: #fff;
-}
-.oo-ui-textInputWidget {
- position: relative;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-textInputWidget input,
-.oo-ui-textInputWidget textarea {
- display: inline-block;
- width: 100%;
- resize: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-textInputWidget > .oo-ui-iconElement-icon,
-.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator {
- position: absolute;
- top: 0;
- height: 100%;
- background-repeat: no-repeat;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-textInputWidget > .oo-ui-iconElement-icon {
- right: 0;
-}
-.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator {
- left: 0;
-}
-.oo-ui-textInputWidget input,
-.oo-ui-textInputWidget textarea {
- padding: .8em 1em;
-}
-.oo-ui-menuWidget {
- position: absolute;
- background: white;
- border: solid 1px #dddddd;
-}
-.oo-ui-menuWidget input {
- position: absolute;
- width: 0;
- height: 0;
- overflow: hidden;
- opacity: 0;
-}
-.oo-ui-menuItemWidget {
- position: relative;
-}
-.oo-ui-menuItemWidget .oo-ui-iconElement-icon {
- display: none;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
- background-color: transparent;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected .oo-ui-iconElement-icon {
- display: block;
-}
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
- background: #347bff;
- color: #ffffff;
-}
-.oo-ui-menuItemWidget .oo-ui-iconElement-icon {
- background-size: 24px auto;
-}
-.oo-ui-menuSectionItemWidget {
- cursor: default;
- font-weight: normal;
- color: #777777;
- border: none;
-}
-.oo-ui-inlineMenuWidget {
- position: relative;
- display: inline-block;
- margin: 0.25em 0;
- min-width: 20em;
-}
-.oo-ui-inlineMenuWidget-handle {
- width: 100%;
- display: inline-block;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- position: absolute;
- background-position: center center;
- background-repeat: no-repeat;
-}
-.oo-ui-inlineMenuWidget .oo-ui-menuWidget {
- z-index: 1;
- width: 100%;
-}
-.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-inlineMenuWidget-handle {
- cursor: default;
-}
-.oo-ui-inlineMenuWidget-handle {
- height: 2.5em;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator,
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- top: 0;
- width: 2.5em;
- height: 2.5em;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatorElement-indicator {
- left: 0;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconElement-icon {
- right: 0.25em;
-}
-.oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- line-height: 2.5em;
- margin: 0 0.5em;
-}
-.oo-ui-inlineMenuWidget.oo-ui-iconElement .oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- margin-right: 3em;
-}
-.oo-ui-inlineMenuWidget.oo-ui-indicatorElement .oo-ui-inlineMenuWidget-handle .oo-ui-labelElement-label {
- margin-left: 2em;
-}
-.oo-ui-outlineItemWidget {
- position: relative;
- cursor: pointer;
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- padding: 0.75em;
-}
-.oo-ui-outlineControlsWidget {
- height: 3em;
-}
-.oo-ui-outlineControlsWidget-items,
-.oo-ui-outlineControlsWidget-movers {
- float: right;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
- float: right;
- background-position: left center;
- background-repeat: no-repeat;
-}
-.oo-ui-outlineControlsWidget-items {
- float: right;
-}
-.oo-ui-outlineControlsWidget-items .oo-ui-buttonWidget {
- float: right;
-}
-.oo-ui-outlineControlsWidget-movers {
- float: left;
-}
-.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
- float: left;
-}
-.oo-ui-outlineControlsWidget-items,
-.oo-ui-outlineControlsWidget-movers {
- height: 2em;
- margin: 0.5em;
- padding: 0;
-}
-.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
- width: 1.5em;
- height: 2em;
- margin: 0.5em 0.5em 0.5em 0;
-}
-.oo-ui-outlineControlsWidget-items {
- margin-right: 0;
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget {
- z-index: 1;
-}
-.oo-ui-comboBoxWidget > .oo-ui-selectWidget > .oo-ui-selectWidget {
- min-width: 20em;
-}
-.oo-ui-searchWidget-query {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
-}
-.oo-ui-searchWidget-query .oo-ui-textInputWidget {
- width: 100%;
-}
-.oo-ui-searchWidget-results {
- position: absolute;
- bottom: 0;
- right: 0;
- left: 0;
- overflow-x: hidden;
- overflow-y: auto;
-}
-.oo-ui-searchWidget-query {
- height: 4em;
- padding: 0 1em;
-}
-.oo-ui-searchWidget-query .oo-ui-textInputWidget {
- margin: 0.75em 0;
-}
-.oo-ui-searchWidget-results {
- top: 4em;
- padding: 1em;
- line-height: 0;
-}
-.oo-ui-window {
- line-height: 1em;
- /* Content div takes focus when opened, so hide outline */
-}
-.oo-ui-window-frame {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-window-frame > iframe {
- width: 100%;
- height: 100%;
- margin: 0;
- padding: 0;
-}
-.oo-ui-window-content:focus {
- outline: none;
-}
-.oo-ui-window-head,
-.oo-ui-window-foot {
- -webkit-touch-callout: none;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
-}
-.oo-ui-window-body {
- margin: 0;
- padding: 0;
- background: none;
-}
-.oo-ui-window-overlay {
- position: absolute;
- top: 0;
- right: 0;
-}
-.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;
- right: 0;
- left: 0;
- overflow: hidden;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-dialog-content > .oo-ui-window-head {
- z-index: 1;
- top: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-body {
- z-index: 2;
- top: 0;
- bottom: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-foot {
- z-index: 1;
- bottom: 0;
-}
-.oo-ui-dialog-content > .oo-ui-window-overlay {
- z-index: 3;
-}
-.oo-ui-messageDialog-actions-horizontal {
- display: table;
- table-layout: fixed;
- width: 100%;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
- display: table-cell;
- width: 1%;
-}
-.oo-ui-messageDialog-actions-vertical {
- display: block;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
- display: block;
- overflow: hidden;
- text-overflow: ellipsis;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget {
- position: relative;
- text-align: center;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-buttonElement-button {
- display: block;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labelElement-label {
- position: relative;
- top: auto;
- bottom: auto;
- display: inline;
- white-space: nowrap;
-}
-.oo-ui-messageDialog-title,
-.oo-ui-messageDialog-message {
- display: block;
- text-align: center;
- padding-top: 0.5em;
-}
-.oo-ui-messageDialog-title {
- font-size: 1.5em;
- line-height: 1em;
- color: #000;
-}
-.oo-ui-messageDialog-message {
- font-size: 0.9em;
- line-height: 1.25em;
- color: #666;
-}
-.oo-ui-messageDialog-message-verbose {
- font-size: 1.1em;
- line-height: 1.5em;
- text-align: right;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
- border-left: solid 1px #e5e5e5;
-}
-.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget:last-child {
- border-left-width: 0;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget {
- border-bottom: solid 1px #e5e5e5;
-}
-.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
- border-bottom-width: 0;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget .oo-ui-labelElement-label {
- text-align: center;
- line-height: 3.4em;
- padding: 0 2em;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget:hover {
- background-color: rgba(0, 0, 0, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget:active {
- background-color: rgba(0, 0, 0, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:hover {
- background-color: rgba(8, 126, 204, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary:active {
- background-color: rgba(8, 126, 204, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
- font-weight: bold;
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:hover {
- background-color: rgba(118, 171, 54, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-constructive:active {
- background-color: rgba(118, 171, 54, 0.1);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:hover {
- background-color: rgba(212, 83, 83, 0.05);
-}
-.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-flaggedElement-destructive:active {
- background-color: rgba(212, 83, 83, 0.1);
-}
-.oo-ui-processDialog-location {
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-.oo-ui-processDialog-title {
- display: inline;
- padding: 0;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget {
- white-space: nowrap;
-}
-.oo-ui-processDialog-actions-safe,
-.oo-ui-processDialog-actions-primary {
- position: absolute;
- top: 0;
- bottom: 0;
-}
-.oo-ui-processDialog-actions-safe {
- right: 0;
-}
-.oo-ui-processDialog-actions-primary {
- left: 0;
-}
-.oo-ui-processDialog-errors {
- display: none;
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- bottom: 0;
- z-index: 2;
- overflow-x: hidden;
- overflow-y: auto;
-}
-.oo-ui-processDialog-content .oo-ui-window-head {
- height: 3.35em;
- border-bottom: 1px solid #dddddd;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-.oo-ui-processDialog-content .oo-ui-window-body {
- top: 3.35em;
- padding: 2em 0;
-}
-.oo-ui-processDialog-navigation {
- position: relative;
- height: 3.35em;
- padding: 0 1em;
-}
-.oo-ui-processDialog-location {
- padding: 0.75em 0;
- height: 1.85em;
- cursor: default;
- text-align: center;
-}
-.oo-ui-processDialog-title {
- font-weight: bold;
- line-height: 1.85em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-buttonElement-button {
- padding: 0.35em 0.75em;
- min-width: 1.85em;
- min-height: 1.85em;
- border: 1px solid #dddddd;
- border-radius: 4px;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-labelElement-label {
- line-height: 1.85em;
- padding: 0 1em;
- font-weight: bold;
- color: #777777;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-iconElement-icon,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-iconElement-icon,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget .oo-ui-iconElement-icon {
- position: absolute;
- margin-top: -0.125em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-framed .oo-ui-buttonElement-button {
- vertical-align: middle;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-buttonElement-button {
- border: 1px solid transparent;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-flaggedElement-destructive .oo-ui-labelElement-label {
- color: #d11d13;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget .oo-ui-buttonElement-button {
- padding: 0.75em 0.35em;
- border: none;
- border-radius: 0;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-buttonElement-button,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-buttonElement-button {
- background-color: #347bff;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-flaggedElement-primary .oo-ui-labelElement-label {
- color: #ffffff;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- right: 0.5em;
-}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-labelElement-label {
- padding-right: 2.25em;
-}
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- left: 0.5em;
-}
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-iconElement .oo-ui-labelElement-label {
- padding-left: 2.25em;
-}
-.oo-ui-processDialog-actions-other {
- position: absolute;
- bottom: 1em;
-}
-.oo-ui-processDialog > .oo-ui-window-frame {
- min-height: 5em;
-}
-.oo-ui-processDialog-errors {
- background-color: rgba(255, 255, 255, 0.9);
- padding: 3em 3em 1.5em 3em;
- text-align: center;
-}
-.oo-ui-processDialog-errors .oo-ui-buttonWidget {
- margin: 2em 1em 2em 1em;
-}
-.oo-ui-processDialog-errors-title {
- font-size: 1.5em;
- color: #000;
- margin-bottom: 2em;
-}
-.oo-ui-processDialog-error {
- text-align: right;
- margin: 1em;
- padding: 1em;
- border: solid 1px #ff9e9e;
- background-color: #fff7f7;
- border-radius: 0.25em;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog {
- position: fixed;
- width: 0;
- height: 0;
- overflow: hidden;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup {
- width: auto;
- height: auto;
- top: 0;
- left: 0;
- bottom: 0;
- right: 0;
- padding: 1em;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame {
- position: fixed;
- left: 0;
- right: 0;
- margin: auto;
- overflow: hidden;
- max-width: 100%;
- max-height: 100%;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-setup > .oo-ui-window-frame > iframe {
- width: 100%;
- height: 100%;
-}
-.oo-ui-windowManager-fullscreen > .oo-ui-dialog > .oo-ui-window-frame {
- width: 100%;
- height: 100%;
- top: 0;
- bottom: 0;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog {
- background-color: rgba(255, 255, 255, 0.5);
- opacity: 0;
- -webkit-transition: opacity 250ms ease-in-out;
- -moz-transition: opacity 250ms ease-in-out;
- -ms-transition: opacity 250ms ease-in-out;
- -o-transition: opacity 250ms ease-in-out;
- transition: opacity 250ms ease-in-out;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
- top: 0;
- bottom: 0;
- background-color: #fff;
- -webkit-transform: translate3d(0, -200%, 0);
- -moz-transform: translate3d(0, -200%, 0);
- -ms-transform: translate3d(0, -200%, 0);
- -o-transform: translate3d(0, -200%, 0);
- transform: translate3d(0, -200%, 0);
- -webkit-transition: transform 250ms ease-in-out;
- -moz-transition: transform 250ms ease-in-out;
- -ms-transition: transform 250ms ease-in-out;
- -o-transition: transform 250ms ease-in-out;
- transition: transform 250ms ease-in-out;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
- opacity: 1;
-}
-.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready > .oo-ui-window-frame {
- -webkit-transform: translate3d(0, 0, 0);
- -moz-transform: translate3d(0, 0, 0);
- -ms-transform: translate3d(0, 0, 0);
- -o-transform: translate3d(0, 0, 0);
- transform: translate3d(0, 0, 0);
-}
-.oo-ui-windowManager-modal.oo-ui-windowManager-floating > .oo-ui-dialog > .oo-ui-window-frame {
- border: solid 1px #ccc;
- border-radius: 0.5em;
- box-shadow: 0 0.2em 1em rgba(0, 0, 0, 0.3);
-}
-
-/*
- * Blank theme mixins.
- *
- * Base styles invoke these mixins at the end of their definitions. Override these mixins to add
- * additional rules to the base styles.
- */
-.oo-ui-icon-check {
- background-image: /* @embed */ url(themes/minerva/images/icons/check.png);
- background: #347bff;
-}
diff --git a/resources/lib/oojs-ui/oojs-ui.css b/resources/lib/oojs-ui/oojs-ui.css
deleted file mode 100644
index fa077068..00000000
--- a/resources/lib/oojs-ui/oojs-ui.css
+++ /dev/null
@@ -1,1159 +0,0 @@
-/*!
- * OOjs UI v0.1.0
- * 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: Fri May 30 2014 12:12:37 GMT-0700 (PDT)
- */
-
-/* Textures */
-
-.oo-ui-texture-pending {
- background-image: /* @embed */ url(images/textures/pending.gif);
-}
-
-.oo-ui-texture-transparency {
- background-image: /* @embed */ url(images/textures/transparency.png);
-}
-
-/* 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;
- /* Fix for strange opacity-related rendering issues.
- CAUTION: -webkit-backface-visibility: hidden; is EXTREMELY DANGEROUS.
- If applied to a VE surface directly, it will break selection of
- FocusableNodes, and in the past it's caused transparent PNGs to
- render as opaque black images. For some reason applying it to the dialog
- wrapper in the main document fixes opacity-related behavior in the iframe
- document, but doesn't break the surface inside the iframe. */
-
- -webkit-backface-visibility: hidden;
- backface-visibility: hidden;
-}
-
-.oo-ui-dialog > .oo-ui-window-frame {
- position: fixed;
- right: 0;
- left: 0;
- min-height: 12em;
- margin: auto;
- overflow: hidden;
-}
-
-.oo-ui-dialog > .oo-ui-window-frame .oo-ui-frame {
- width: 100%;
- height: 100%;
-}
-
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-buttonedElement-framed {
- float: left;
-}
-
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-flaggableElement-primary,
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-flaggableElement-constructive,
-.oo-ui-dialog-content .oo-ui-window-foot .oo-ui-flaggableElement-destructive {
- float: right;
-}
-
-.oo-ui-dialog-content-footless .oo-ui-window-foot {
- display: none;
-}
-
-.oo-ui-frame {
- padding: 0;
- margin: 0;
-}
-
-.oo-ui-frame-body {
- padding: 0;
- margin: 0;
- background: none;
-}
-
-.oo-ui-frame-content:focus {
- outline: none;
-}
-
-.oo-ui-toolbar {
- clear: both;
-}
-
-.oo-ui-toolbar-bar {
- line-height: 1em;
-}
-
-.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;
- user-select: none;
- -webkit-touch-callout: none;
-}
-
-.oo-ui-toolbar-actions .oo-ui-popupWidget {
- -webkit-user-select: all;
- -moz-user-select: all;
- -ms-user-select: all;
- user-select: all;
- -webkit-touch-callout: default;
-}
-
-.oo-ui-toolbar-shadow {
- position: absolute;
- width: 100%;
- pointer-events: none;
- background-position: left top;
- background-repeat: repeat-x;
-}
-
-.oo-ui-toolGroup {
- display: inline-block;
- margin: 0.3em;
- vertical-align: middle;
-}
-
-.oo-ui-toolGroup-empty {
- display: none;
-}
-
-.oo-ui-toolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
- background-position: center center;
- background-repeat: no-repeat;
-}
-
-.oo-ui-window-head {
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-touch-callout: none;
-}
-
-.oo-ui-window-icon {
- float: left;
- background-position: center center;
- background-repeat: no-repeat;
-}
-
-.oo-ui-window-title {
- float: left;
- white-space: nowrap;
- cursor: default;
-}
-
-.oo-ui-window-overlay {
- position: absolute;
- top: 0;
- left: 0;
-}
-
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button {
- display: inline-block;
- vertical-align: middle;
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-touch-callout: none;
-}
-
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-iconedElement-icon {
- display: none;
- margin-left: 0;
-}
-
-.oo-ui-buttonedElement .oo-ui-buttonedElement-button > .oo-ui-indicatedElement-indicator {
- display: none;
- margin-right: -0.75em;
-}
-
-.oo-ui-buttonedElement.oo-ui-widget-disabled .oo-ui-buttonedElement-button {
- cursor: default;
-}
-
-.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 {
- display: inline-block;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
-}
-
-.oo-ui-buttonedElement-frameless {
- position: relative;
- display: inline-block;
-}
-
-.oo-ui-buttonedElement-frameless .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
- display: inline-block;
- margin-left: 0.25em;
- vertical-align: middle;
-}
-
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
- display: inline-block;
- text-align: center;
- vertical-align: top;
-}
-
-.oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button > .oo-ui-labeledElement-label {
- display: inline-block;
- line-height: 1.9em;
- vertical-align: middle;
-}
-
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-active,
-.oo-ui-buttonedElement-framed.oo-ui-widget-disabled .oo-ui-buttonedElement-button.oo-ui-buttonedElement-pressed {
- cursor: default;
-}
-
-.oo-ui-clippableElement-clippable {
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-.oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous .oo-ui-panelLayout-scrollable {
- overflow-y: hidden;
-}
-
-.oo-ui-bookletLayout-stackLayout .oo-ui-panelLayout {
- 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-editable .oo-ui-outlineWidget {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 3em;
- left: 0;
- overflow-y: auto;
-}
-
-.oo-ui-bookletLayout-outlinePanel .oo-ui-outlineControlsWidget {
- position: absolute;
- right: 0;
- bottom: 0;
- left: 0;
-}
-
-.oo-ui-fieldLayout {
- margin-bottom: 1em;
-}
-
-.oo-ui-fieldLayout:last-child {
- margin-bottom: 0;
-}
-
-.oo-ui-fieldLayout:before,
-.oo-ui-fieldLayout:after {
- display: table;
- content: " ";
-}
-
-.oo-ui-fieldLayout:after {
- clear: both;
-}
-
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-labeledElement-label,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labeledElement-label {
- display: block;
- float: left;
- width: 35%;
- padding-top: 0.5em;
- margin-right: 5%;
-}
-
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-left > .oo-ui-fieldLayout-field,
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-fieldLayout-field {
- display: block;
- float: left;
- width: 60%;
-}
-
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-right > .oo-ui-labeledElement-label {
- text-align: right;
-}
-
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-labeledElement-label {
- display: inline-block;
- padding: 0.75em 0.5em 0.5em 0.5em;
- vertical-align: middle;
-}
-
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline > .oo-ui-fieldLayout-field {
- display: inline-block;
- padding: 0.5em 0;
- vertical-align: middle;
-}
-
-.oo-ui-fieldLayout.oo-ui-fieldLayout-align-top > .oo-ui-labeledElement-label {
- padding: 0.5em 0;
-}
-
-.oo-ui-fieldsetLayout {
- position: relative;
- padding: 0;
- margin: 0;
-}
-
-.oo-ui-fieldsetLayout + .oo-ui-fieldsetLayout {
- margin-top: 2em;
-}
-
-.oo-ui-fieldsetLayout-labeled {
- margin-top: -0.75em;
-}
-
-.oo-ui-fieldsetLayout > .oo-ui-labeledElement-label {
- padding: 0.25em 0;
- margin-bottom: 0.5em;
-}
-
-.oo-ui-fieldsetLayout.oo-ui-iconedElement > .oo-ui-labeledElement-label {
- padding-left: 1.75em;
- line-height: 1.33em;
-}
-
-.oo-ui-fieldsetLayout.oo-ui-iconedElement > .oo-ui-iconedElement-icon {
- position: absolute;
- top: 0.25em;
- left: 0;
- display: block;
- width: 2em;
- height: 2em;
- background-position: center center;
- background-repeat: no-repeat;
-}
-
-.oo-ui-gridLayout {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
-}
-
-.oo-ui-labelWidget {
- padding: 0.5em 0;
-}
-
-.oo-ui-panelLayout-scrollable {
- overflow-y: auto;
-}
-
-.oo-ui-stackLayout > .oo-ui-panelLayout {
- display: none;
-}
-
-.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
- position: relative;
- display: block;
-}
-
-.oo-ui-barToolGroup > .oo-ui-iconedElement-icon,
-.oo-ui-barToolGroup > .oo-ui-labeledElement-label {
- display: none;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool {
- position: relative;
- display: inline-block;
- vertical-align: top;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool-link {
- display: block;
- height: 1.5em;
- padding: 0.25em;
-}
-
-.oo-ui-barToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
- display: block;
- width: 1.5em;
- height: 1.5em;
-}
-
-.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-title,
-.oo-ui-barToolGroup .oo-ui-tool-accel {
- display: none;
-}
-
-.oo-ui-barToolGroup.oo-ui-widget-enabled .oo-ui-tool-link {
- cursor: pointer;
-}
-
-.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;
-}
-
-.oo-ui-listToolGroup .oo-ui-tool-link {
- display: block;
- padding-right: 0.5em;
- white-space: nowrap;
- cursor: pointer;
-}
-
-.oo-ui-listToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
-
-.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;
- padding: 0.25em 1em 0.25em 0.25em;
- white-space: nowrap;
- cursor: pointer;
-}
-
-.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 {
- background-image: /* @embed */ url(images/icons/check.png);
-}
-
-.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-disabled .oo-ui-tool-link {
- cursor: default;
-}
-
-.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;
-}
-
-.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 {
- margin: 0 1em;
- font-size: 0.8em;
- line-height: 2.6em;
-}
-
-.oo-ui-popupToolGroup-header {
- margin: 0 0.6em;
- font-size: 0.8em;
- font-weight: bold;
- line-height: 2.6em;
-}
-
-.oo-ui-popupToolGroup.oo-ui-widget-disabled .oo-ui-popupToolGroup-handle {
- cursor: default;
-}
-
-.oo-ui-popupToolGroup.oo-ui-iconedElement .oo-ui-popupToolGroup-handle .oo-ui-labeledElement-label {
- margin-left: 3em;
-}
-
-.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 {
- position: absolute;
- top: 2em;
- left: -1px;
- z-index: 4;
- display: none;
-}
-
-.oo-ui-popupToolGroup .oo-ui-toolGroup-tools .oo-ui-iconedElement-icon {
- background-position: center center;
- background-repeat: no-repeat;
-}
-
-.oo-ui-popupToolGroup-active.oo-ui-widget-enabled > .oo-ui-toolGroup-tools {
- display: block;
-}
-
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconedElement-icon {
- display: inline-block;
- width: 2em;
- height: 2em;
- margin-right: 0.25em;
- vertical-align: middle;
-}
-
-.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
- display: inline-block;
- font-size: 0.8em;
- line-height: 2em;
- vertical-align: middle;
-}
-
-.oo-ui-popupToolGroup .oo-ui-tool-accel {
- display: none;
-}
-
-.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-iconWidget {
- display: inline-block;
- width: 1.9em;
- height: 1.9em;
- line-height: 2.5em;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- opacity: 0.8;
-}
-
-.oo-ui-iconWidget.oo-ui-widget-disabled {
- opacity: 0.2;
-}
-
-.oo-ui-indicatorWidget {
- display: inline-block;
- width: 1.9em;
- height: 1.9em;
- line-height: 2.5em;
- vertical-align: middle;
- background-position: center center;
- background-repeat: no-repeat;
- opacity: 0.8;
-}
-
-.oo-ui-indicatorWidget.oo-ui-widget-disabled {
- opacity: 0.2;
-}
-
-.oo-ui-selectWidget {
- padding: 0;
- margin: 0;
- list-style: none;
-}
-
-.oo-ui-optionWidget {
- position: relative;
- display: block;
- margin: 0;
- list-style: none;
- cursor: pointer;
- border: none;
-}
-
-.oo-ui-optionWidget.oo-ui-widget-disabled {
- cursor: default;
-}
-
-.oo-ui-optionWidget .oo-ui-labeledElement-label {
- display: block;
- overflow: hidden;
- line-height: 1.5em;
- text-overflow: ellipsis;
- white-space: nowrap;
-}
-
-.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-position: center center;
- background-repeat: no-repeat;
-}
-
-.oo-ui-optionWidget .oo-ui-iconedElement-icon {
- left: 0.5em;
-}
-
-.oo-ui-optionWidget .oo-ui-indicatedElement-indicator {
- right: 0.5em;
-}
-
-.oo-ui-menuWidget {
- position: absolute;
-}
-
-.oo-ui-menuWidget input {
- position: absolute;
- width: 0;
- height: 0;
- overflow: hidden;
- opacity: 0;
-}
-
-.oo-ui-popupWidget-popup {
- position: absolute;
- overflow: hidden;
-}
-
-.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 {
- position: absolute;
- display: block;
- background-repeat: no-repeat;
-}
-
-.oo-ui-popupWidget-head {
- height: 2.5em;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-touch-callout: 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 {
- clear: both;
-}
-
-.oo-ui-buttonGroupWidget {
- border-radius: 0.3em;
-}
-
-.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed .oo-ui-buttonedElement-button {
- margin-bottom: -1px;
- margin-left: -1px;
- border-radius: 0;
-}
-
-.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed:first-child .oo-ui-buttonedElement-button {
- margin-left: 0;
- border-bottom-left-radius: 0.3em;
- border-top-left-radius: 0.3em;
-}
-
-.oo-ui-buttonGroupWidget .oo-ui-buttonedElement-framed:last-child .oo-ui-buttonedElement-button {
- border-top-right-radius: 0.3em;
- border-bottom-right-radius: 0.3em;
-}
-
-.oo-ui-buttonOptionWidget {
- display: inline-block;
- 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;
- height: 1.9em;
- margin-top: 0;
- vertical-align: middle;
-}
-
-.oo-ui-buttonSelectWidget {
- display: inline-block;
- white-space: nowrap;
-}
-
-.oo-ui-buttonWidget {
- display: inline-block;
- vertical-align: middle;
-}
-
-.oo-ui-inlineMenuWidget {
- position: relative;
- display: inline-block;
- min-width: 20em;
- margin: 0.25em 0;
-}
-
-.oo-ui-inlineMenuWidget-handle {
- display: inline-block;
- width: 100%;
- height: 2.5em;
- cursor: pointer;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-touch-callout: none;
-}
-
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatedElement-indicator,
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconedElement-icon {
- position: absolute;
- top: 0;
- width: 2.5em;
- height: 2.5em;
- background-position: center center;
- background-repeat: no-repeat;
-}
-
-.oo-ui-inlineMenuWidget-handle .oo-ui-indicatedElement-indicator {
- right: 0;
-}
-
-.oo-ui-inlineMenuWidget-handle .oo-ui-iconedElement-icon {
- left: 0.25em;
-}
-
-.oo-ui-inlineMenuWidget-handle .oo-ui-labeledElement-label {
- margin: 0 0.5em;
- line-height: 2.5em;
-}
-
-.oo-ui-inlineMenuWidget.oo-ui-iconedElement .oo-ui-inlineMenuWidget-handle .oo-ui-labeledElement-label {
- margin-left: 3em;
-}
-
-.oo-ui-inlineMenuWidget.oo-ui-indicatedElement .oo-ui-inlineMenuWidget-handle .oo-ui-labeledElement-label {
- margin-right: 2em;
-}
-
-.oo-ui-inlineMenuWidget .oo-ui-menuWidget {
- z-index: 1;
- width: 100%;
-}
-
-.oo-ui-inlineMenuWidget.oo-ui-widget-disabled .oo-ui-inlineMenuWidget-handle {
- cursor: default;
-}
-
-.oo-ui-menuItemWidget {
- position: relative;
-}
-
-.oo-ui-menuItemWidget .oo-ui-iconedElement-icon {
- display: none;
-}
-
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected {
- background-color: transparent;
-}
-
-.oo-ui-menuItemWidget.oo-ui-optionWidget-selected .oo-ui-iconedElement-icon {
- display: block;
-}
-
-.oo-ui-menuSectionItemWidget {
- cursor: default;
-}
-
-.oo-ui-outlineControlsWidget {
- height: 3em;
-}
-
-.oo-ui-outlineControlsWidget-adders,
-.oo-ui-outlineControlsWidget-movers {
- float: left;
- height: 2em;
- padding: 0;
- margin: 0.5em;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-.oo-ui-outlineControlsWidget > .oo-ui-iconedElement-icon {
- float: left;
- width: 1.5em;
- height: 2em;
- margin: 0.5em 0 0.5em 0.5em;
- background-position: right center;
- background-repeat: no-repeat;
-}
-
-.oo-ui-outlineControlsWidget-adders {
- float: left;
- margin-left: 0;
-}
-
-.oo-ui-outlineControlsWidget-adders .oo-ui-buttonWidget {
- float: left;
-}
-
-.oo-ui-outlineControlsWidget-movers {
- float: right;
-}
-
-.oo-ui-outlineControlsWidget-movers .oo-ui-buttonWidget {
- float: right;
-}
-
-.oo-ui-outlineItemWidget {
- position: relative;
- padding: 0.75em;
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-touch-callout: none;
-}
-
-.oo-ui-popupButtonWidget {
- position: relative;
-}
-
-.oo-ui-popupButtonWidget .oo-ui-popupWidget {
- position: absolute;
- left: 1em;
- cursor: auto;
-}
-
-.oo-ui-searchWidget-query {
- position: absolute;
- top: 0;
- right: 0;
- left: 0;
- height: 4em;
- padding: 0 1em;
-}
-
-.oo-ui-searchWidget-query .oo-ui-textInputWidget {
- width: 100%;
- margin: 0.75em 0;
-}
-
-.oo-ui-searchWidget-results {
- position: absolute;
- top: 4em;
- right: 0;
- bottom: 0;
- left: 0;
- padding: 1em;
- overflow-x: hidden;
- overflow-y: auto;
- line-height: 0;
-}
-
-.oo-ui-textInputWidget {
- position: relative;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-.oo-ui-textInputWidget input,
-.oo-ui-textInputWidget textarea {
- display: inline-block;
- width: 100%;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- resize: none;
-}
-
-.oo-ui-textInputWidget-icon {
- position: absolute;
- top: 0;
- left: 0;
- height: 100%;
- background-position: right center;
- background-repeat: no-repeat;
-}
-
-.oo-ui-toggleSwitchWidget {
- position: relative;
- display: inline-block;
- width: 4em;
- height: 2em;
- overflow: hidden;
- vertical-align: middle;
- cursor: pointer;
- -webkit-transform: translateZ(0);
- -moz-transform: translateZ(0);
- -ms-transform: translateZ(0);
- -o-transform: translateZ(0);
- transform: translateZ(0);
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
-}
-
-.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
- cursor: default;
-}
-
-.oo-ui-toggleSwitchWidget-grip {
- position: absolute;
- top: 0.25em;
- left: 0.25em;
- display: block;
- width: 1.5em;
- height: 1.5em;
- -webkit-box-sizing: border-box;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- -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;
- -ms-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 .oo-ui-toggleSwitchWidget-glow {
- position: absolute;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- -webkit-transition: opacity 200ms ease-in-out;
- -moz-transition: opacity 200ms ease-in-out;
- -ms-transition: opacity 200ms ease-in-out;
- -o-transition: opacity 200ms ease-in-out;
- transition: opacity 200ms ease-in-out;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- -webkit-touch-callout: none;
-}
-
-.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
- left: 2.25em;
- margin-left: -2px;
-}
-
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-grip {
- left: 0.25em;
- margin-left: 0;
-}
-
-.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
- display: none;
-}
-
-/* Icons */
-
-.oo-ui-icon-add-item {
- background-image: /* @embed */ url(images/icons/add-item.png);
-}
-
-.oo-ui-icon-advanced {
- background-image: /* @embed */ url(images/icons/advanced.png);
-}
-
-.oo-ui-icon-alert {
- background-image: /* @embed */ url(images/icons/alert.png);
-}
-
-.oo-ui-icon-check {
- background-image: /* @embed */ url(images/icons/check.png);
-}
-
-.oo-ui-icon-clear {
- background-image: /* @embed */ url(images/icons/clear.png);
-}
-
-.oo-ui-icon-close {
- background-image: /* @embed */ url(images/icons/close.png);
-}
-
-.oo-ui-icon-code {
- background-image: /* @embed */ url(images/icons/code.png);
-}
-
-.oo-ui-icon-collapse {
- background-image: /* @embed */ url(images/icons/collapse.png);
-}
-
-.oo-ui-icon-comment {
- background-image: /* @embed */ url(images/icons/comment.png);
-}
-
-.oo-ui-icon-expand {
- background-image: /* @embed */ url(images/icons/expand.png);
-}
-
-.oo-ui-icon-help {
- background-image: /* @embed */ url(images/icons/help.png);
-}
-
-.oo-ui-icon-info {
- background-image: /* @embed */ url(images/icons/info.png);
-}
-
-.oo-ui-icon-link {
- background-image: /* @embed */ url(images/icons/link.png);
-}
-
-.oo-ui-icon-menu {
- background-image: /* @embed */ url(images/icons/menu.png);
-}
-
-.oo-ui-icon-next {
- background-image: /* @embed */ url(images/icons/move-ltr.png);
-}
-
-.oo-ui-icon-picture {
- background-image: /* @embed */ url(images/icons/picture.png);
-}
-
-.oo-ui-icon-previous {
- background-image: /* @embed */ url(images/icons/move-rtl.png);
-}
-
-.oo-ui-icon-redo {
- background-image: /* @embed */ url(images/icons/arched-arrow-ltr.png);
-}
-
-.oo-ui-icon-remove {
- background-image: /* @embed */ url(images/icons/remove.png);
-}
-
-.oo-ui-icon-search {
- background-image: /* @embed */ url(images/icons/search.png);
-}
-
-.oo-ui-icon-settings {
- background-image: /* @embed */ url(images/icons/settings.png);
-}
-
-.oo-ui-icon-tag {
- background-image: /* @embed */ url(images/icons/tag.png);
-}
-
-.oo-ui-icon-undo {
- background-image: /* @embed */ url(images/icons/arched-arrow-rtl.png);
-}
-
-.oo-ui-icon-window {
- background-image: /* @embed */ url(images/icons/window.png);
-}
-
-/* Indicators */
-
-.oo-ui-indicator-alert {
- background-image: /* @embed */ url(images/indicators/alert.png);
-}
-
-.oo-ui-indicator-down {
- background-image: /* @embed */ url(images/indicators/down.png);
-}
-
-.oo-ui-indicator-required {
- background-image: /* @embed */ url(images/indicators/required.png);
-}
-
-.oo-ui-indicator-up {
- background-image: /* @embed */ url(images/indicators/up.png);
-} \ No newline at end of file
diff --git a/resources/lib/oojs-ui/oojs-ui.js b/resources/lib/oojs-ui/oojs-ui.js
index 33c8238d..9692d5cf 100644
--- a/resources/lib/oojs-ui/oojs-ui.js
+++ b/resources/lib/oojs-ui/oojs-ui.js
@@ -1,12 +1,12 @@
/*!
- * OOjs UI v0.1.0-pre (f2c3f12959)
+ * OOjs UI v0.11.3
* https://www.mediawiki.org/wiki/OOjs_UI
*
- * Copyright 2011–2014 OOjs Team and other contributors.
+ * Copyright 2011–2015 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2014-09-18T23:22:20Z
+ * Date: 2015-05-12T12:15:37Z
*/
( function ( OO ) {
@@ -45,6 +45,39 @@ OO.ui.Keys = {
};
/**
+ * Check if an element is focusable.
+ * Inspired from :focusable in jQueryUI v1.11.4 - 2015-04-14
+ *
+ * @param {jQuery} element Element to test
+ * @return {Boolean} [description]
+ */
+OO.ui.isFocusableElement = function ( $element ) {
+ var node = $element[0],
+ nodeName = node.nodeName.toLowerCase(),
+ // Check if the element have tabindex set
+ isInElementGroup = /^(input|select|textarea|button|object)$/.test( nodeName ),
+ // Check if the element is a link with href or if it has tabindex
+ isOtherElement = (
+ ( nodeName === 'a' && node.href ) ||
+ !isNaN( $element.attr( 'tabindex' ) )
+ ),
+ // Check if the element is visible
+ isVisible = (
+ // This is quicker than calling $element.is( ':visible' )
+ $.expr.filters.visible( node ) &&
+ // Check that all parents are visible
+ !$element.parents().addBack().filter( function () {
+ return $.css( this, 'visibility' ) === 'hidden';
+ } ).length
+ );
+
+ return (
+ ( isInElementGroup ? !node.disabled : isOtherElement ) &&
+ isVisible
+ );
+};
+
+/**
* Get the user's language and any fallback languages.
*
* These language codes are used to localize user interface elements in the user's language.
@@ -70,29 +103,100 @@ OO.ui.getLocalValue = function ( obj, lang, fallback ) {
var i, len, langs;
// Requested language
- if ( obj[lang] ) {
- return obj[lang];
+ 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];
+ lang = langs[ i ];
+ if ( obj[ lang ] ) {
+ return obj[ lang ];
}
}
// Fallback language
- if ( obj[fallback] ) {
- return obj[fallback];
+ if ( obj[ fallback ] ) {
+ return obj[ fallback ];
}
// First existing language
for ( lang in obj ) {
- return obj[lang];
+ return obj[ lang ];
}
return undefined;
};
+/**
+ * Check if a node is contained within another node
+ *
+ * Similar to jQuery#contains except a list of containers can be supplied
+ * and a boolean argument allows you to include the container in the match list
+ *
+ * @param {HTMLElement|HTMLElement[]} containers Container node(s) to search in
+ * @param {HTMLElement} contained Node to find
+ * @param {boolean} [matchContainers] Include the container(s) in the list of nodes to match, otherwise only match descendants
+ * @return {boolean} The node is in the list of target nodes
+ */
+OO.ui.contains = function ( containers, contained, matchContainers ) {
+ var i;
+ if ( !Array.isArray( containers ) ) {
+ containers = [ containers ];
+ }
+ for ( i = containers.length - 1; i >= 0; i-- ) {
+ if ( ( matchContainers && contained === containers[ i ] ) || $.contains( containers[ i ], contained ) ) {
+ return true;
+ }
+ }
+ return false;
+};
+
+/**
+ * Return a function, that, as long as it continues to be invoked, will not
+ * be triggered. The function will be called after it stops being called for
+ * N milliseconds. If `immediate` is passed, trigger the function on the
+ * leading edge, instead of the trailing.
+ *
+ * Ported from: http://underscorejs.org/underscore.js
+ *
+ * @param {Function} func
+ * @param {number} wait
+ * @param {boolean} immediate
+ * @return {Function}
+ */
+OO.ui.debounce = function ( func, wait, immediate ) {
+ var timeout;
+ return function () {
+ var context = this,
+ args = arguments,
+ later = function () {
+ timeout = null;
+ if ( !immediate ) {
+ func.apply( context, args );
+ }
+ };
+ if ( immediate && !timeout ) {
+ func.apply( context, args );
+ }
+ clearTimeout( timeout );
+ timeout = setTimeout( later, wait );
+ };
+};
+
+/**
+ * Reconstitute a JavaScript object corresponding to a widget created by
+ * the PHP implementation.
+ *
+ * This is an alias for `OO.ui.Element.static.infuse()`.
+ *
+ * @param {string|HTMLElement|jQuery} idOrNode
+ * A DOM id (if a string) or node for the widget to infuse.
+ * @return {OO.ui.Element}
+ * The `OO.ui.Element` corresponding to this (infusable) document node.
+ */
+OO.ui.infuse = function ( idOrNode ) {
+ return OO.ui.Element.static.infuse( idOrNode );
+};
+
( function () {
/**
* Message store for the default implementation of OO.ui.msg
@@ -111,6 +215,10 @@ OO.ui.getLocalValue = function ( obj, lang, fallback ) {
'ooui-outline-control-remove': 'Remove item',
// Label for the toolbar group that contains a list of all other available tools
'ooui-toolbar-more': 'More',
+ // Label for the fake tool that expands the full list of tools in a toolbar group
+ 'ooui-toolgroup-expand': 'More',
+ // Label for the fake tool that collapses the full list of tools in a toolbar group
+ 'ooui-toolgroup-collapse': 'Fewer',
// Default label for the accept button of a confirmation dialog
'ooui-dialog-message-accept': 'OK',
// Default label for the reject button of a confirmation dialog
@@ -119,8 +227,10 @@ OO.ui.getLocalValue = function ( obj, lang, fallback ) {
'ooui-dialog-process-error': 'Something went wrong',
// Label for process dialog dismiss error button, visible when describing errors
'ooui-dialog-process-dismiss': 'Dismiss',
- // Label for process dialog retry action button, visible when describing recoverable errors
- 'ooui-dialog-process-retry': 'Try again'
+ // Label for process dialog retry action button, visible when describing only recoverable errors
+ 'ooui-dialog-process-retry': 'Try again',
+ // Label for process dialog retry action button, visible when describing only warnings
+ 'ooui-dialog-process-continue': 'Continue'
};
/**
@@ -141,12 +251,13 @@ OO.ui.getLocalValue = function ( obj, lang, fallback ) {
* @return {string} Translated message with parameters substituted
*/
OO.ui.msg = function ( key ) {
- var message = messages[key], params = Array.prototype.slice.call( arguments, 1 );
+ 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;
+ return params[ i - 1 ] !== undefined ? params[ i - 1 ] : '$' + n;
} );
} else {
// Return placeholder if message not found
@@ -196,9 +307,10 @@ OO.ui.getLocalValue = function ( obj, lang, fallback ) {
*
* @constructor
* @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$pending] Element to mark as pending, defaults to this.$element
*/
OO.ui.PendingElement = function OoUiPendingElement( config ) {
- // Config initialisation
+ // Configuration initialization
config = config || {};
// Properties
@@ -248,6 +360,7 @@ OO.ui.PendingElement.prototype.isPending = function () {
OO.ui.PendingElement.prototype.pushPending = function () {
if ( this.pending === 0 ) {
this.$pending.addClass( 'oo-ui-pendingElement-pending' );
+ this.updateThemeClasses();
}
this.pending++;
@@ -264,6 +377,7 @@ OO.ui.PendingElement.prototype.pushPending = function () {
OO.ui.PendingElement.prototype.popPending = function () {
if ( this.pending === 1 ) {
this.$pending.removeClass( 'oo-ui-pendingElement-pending' );
+ this.updateThemeClasses();
}
this.pending = Math.max( 0, this.pending - 1 );
@@ -271,7 +385,76 @@ OO.ui.PendingElement.prototype.popPending = function () {
};
/**
- * List of actions.
+ * ActionSets manage the behavior of the {@link OO.ui.ActionWidget action widgets} that comprise them.
+ * Actions can be made available for specific contexts (modes) and circumstances
+ * (abilities). Action sets are primarily used with {@link OO.ui.Dialog Dialogs}.
+ *
+ * ActionSets contain two types of actions:
+ *
+ * - Special: Special actions are the first visible actions with special flags, such as 'safe' and 'primary', the default special flags. Additional special flags can be configured in subclasses with the static #specialFlags property.
+ * - Other: Other actions include all non-special visible actions.
+ *
+ * Please see the [OOjs UI documentation on MediaWiki][1] for more information.
+ *
+ * @example
+ * // Example: An action set used in a process dialog
+ * function MyProcessDialog( config ) {
+ * MyProcessDialog.super.call( this, config );
+ * }
+ * OO.inheritClass( MyProcessDialog, OO.ui.ProcessDialog );
+ * MyProcessDialog.static.title = 'An action set in a process dialog';
+ * // An action set that uses modes ('edit' and 'help' mode, in this example).
+ * MyProcessDialog.static.actions = [
+ * { action: 'continue', modes: 'edit', label: 'Continue', flags: [ 'primary', 'constructive' ] },
+ * { action: 'help', modes: 'edit', label: 'Help' },
+ * { modes: 'edit', label: 'Cancel', flags: 'safe' },
+ * { action: 'back', modes: 'help', label: 'Back', flags: 'safe' }
+ * ];
+ *
+ * MyProcessDialog.prototype.initialize = function () {
+ * MyProcessDialog.super.prototype.initialize.apply( this, arguments );
+ * this.panel1 = new OO.ui.PanelLayout( { padded: true, expanded: false } );
+ * this.panel1.$element.append( '<p>This dialog uses an action set (continue, help, cancel, back) configured with modes. This is edit mode. Click \'help\' to see help mode.</p>' );
+ * this.panel2 = new OO.ui.PanelLayout( { padded: true, expanded: false } );
+ * this.panel2.$element.append( '<p>This is help mode. Only the \'back\' action widget is configured to be visible here. Click \'back\' to return to \'edit\' mode.</p>' );
+ * this.stackLayout = new OO.ui.StackLayout( {
+ * items: [ this.panel1, this.panel2 ]
+ * } );
+ * this.$body.append( this.stackLayout.$element );
+ * };
+ * MyProcessDialog.prototype.getSetupProcess = function ( data ) {
+ * return MyProcessDialog.super.prototype.getSetupProcess.call( this, data )
+ * .next( function () {
+ * this.actions.setMode( 'edit' );
+ * }, this );
+ * };
+ * MyProcessDialog.prototype.getActionProcess = function ( action ) {
+ * if ( action === 'help' ) {
+ * this.actions.setMode( 'help' );
+ * this.stackLayout.setItem( this.panel2 );
+ * } else if ( action === 'back' ) {
+ * this.actions.setMode( 'edit' );
+ * this.stackLayout.setItem( this.panel1 );
+ * } else if ( action === 'continue' ) {
+ * var dialog = this;
+ * return new OO.ui.Process( function () {
+ * dialog.close();
+ * } );
+ * }
+ * return MyProcessDialog.super.prototype.getActionProcess.call( this, action );
+ * };
+ * MyProcessDialog.prototype.getBodyHeight = function () {
+ * return this.panel1.$element.outerHeight( true );
+ * };
+ * var windowManager = new OO.ui.WindowManager();
+ * $( 'body' ).append( windowManager.$element );
+ * var dialog = new MyProcessDialog( {
+ * size: 'medium'
+ * } );
+ * windowManager.addWindows( [ dialog ] );
+ * windowManager.openWindow( dialog );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Action_sets
*
* @abstract
* @class
@@ -281,7 +464,7 @@ OO.ui.PendingElement.prototype.popPending = function () {
* @param {Object} [config] Configuration options
*/
OO.ui.ActionSet = function OoUiActionSet( config ) {
- // Configuration intialization
+ // Configuration initialization
config = config || {};
// Mixin constructors
@@ -309,7 +492,11 @@ OO.mixinClass( OO.ui.ActionSet, OO.EventEmitter );
/* Static Properties */
/**
- * Symbolic name of dialog.
+ * Symbolic name of the flags used to identify special actions. Special actions are displayed in the
+ * header of a {@link OO.ui.ProcessDialog process dialog}.
+ * See the [OOjs UI documentation on MediaWiki][2] for more information and examples.
+ *
+ * [2]:https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs
*
* @abstract
* @static
@@ -322,26 +509,43 @@ OO.ui.ActionSet.static.specialFlags = [ 'safe', 'primary' ];
/**
* @event click
+ *
+ * A 'click' event is emitted when an action is clicked.
+ *
* @param {OO.ui.ActionWidget} action Action that was clicked
*/
/**
* @event resize
+ *
+ * A 'resize' event is emitted when an action widget is resized.
+ *
* @param {OO.ui.ActionWidget} action Action that was resized
*/
/**
* @event add
+ *
+ * An 'add' event is emitted when actions are {@link #method-add added} to the action set.
+ *
* @param {OO.ui.ActionWidget[]} added Actions added
*/
/**
* @event remove
+ *
+ * A 'remove' event is emitted when actions are {@link #method-remove removed}
+ * or {@link #clear cleared}.
+ *
* @param {OO.ui.ActionWidget[]} added Actions removed
*/
/**
* @event change
+ *
+ * A 'change' event is emitted when actions are {@link #method-add added}, {@link #clear cleared},
+ * or {@link #method-remove removed} from the action set or when the {@link #setMode mode} is changed.
+ *
*/
/* Methods */
@@ -349,6 +553,7 @@ OO.ui.ActionSet.static.specialFlags = [ 'safe', 'primary' ];
/**
* Handle action change events.
*
+ * @private
* @fires change
*/
OO.ui.ActionSet.prototype.onActionChange = function () {
@@ -361,7 +566,7 @@ OO.ui.ActionSet.prototype.onActionChange = function () {
};
/**
- * Check if a action is one of the special actions.
+ * Check if an action is one of the special actions.
*
* @param {OO.ui.ActionWidget} action Action to check
* @return {boolean} Action is special
@@ -370,7 +575,7 @@ OO.ui.ActionSet.prototype.isSpecial = function ( action ) {
var flag;
for ( flag in this.special ) {
- if ( action === this.special[flag] ) {
+ if ( action === this.special[ flag ] ) {
return true;
}
}
@@ -379,15 +584,16 @@ OO.ui.ActionSet.prototype.isSpecial = function ( action ) {
};
/**
- * Get actions.
+ * Get action widgets based on the specified filter: ‘actions’, ‘flags’, ‘modes’, ‘visible’,
+ * or ‘disabled’.
*
* @param {Object} [filters] Filters to use, omit to get all actions
- * @param {string|string[]} [filters.actions] Actions that actions must have
- * @param {string|string[]} [filters.flags] Flags that actions must have
- * @param {string|string[]} [filters.modes] Modes that actions must have
- * @param {boolean} [filters.visible] Actions must be visible
- * @param {boolean} [filters.disabled] Actions must be disabled
- * @return {OO.ui.ActionWidget[]} Actions matching all criteria
+ * @param {string|string[]} [filters.actions] Actions that action widgets must have
+ * @param {string|string[]} [filters.flags] Flags that action widgets must have (e.g., 'safe')
+ * @param {string|string[]} [filters.modes] Modes that action widgets must have
+ * @param {boolean} [filters.visible] Action widgets must be visible
+ * @param {boolean} [filters.disabled] Action widgets must be disabled
+ * @return {OO.ui.ActionWidget[]} Action widgets matching all criteria
*/
OO.ui.ActionSet.prototype.get = function ( filters ) {
var i, len, list, category, actions, index, match, matches;
@@ -398,13 +604,13 @@ OO.ui.ActionSet.prototype.get = function ( filters ) {
// Collect category candidates
matches = [];
for ( category in this.categorized ) {
- list = filters[category];
+ list = filters[ category ];
if ( list ) {
if ( !Array.isArray( list ) ) {
list = [ list ];
}
for ( i = 0, len = list.length; i < len; i++ ) {
- actions = this.categorized[category][list[i]];
+ actions = this.categorized[ category ][ list[ i ] ];
if ( Array.isArray( actions ) ) {
matches.push.apply( matches, actions );
}
@@ -413,7 +619,7 @@ OO.ui.ActionSet.prototype.get = function ( filters ) {
}
// Remove by boolean filters
for ( i = 0, len = matches.length; i < len; i++ ) {
- match = matches[i];
+ match = matches[ i ];
if (
( filters.visible !== undefined && match.isVisible() !== filters.visible ) ||
( filters.disabled !== undefined && match.isDisabled() !== filters.disabled )
@@ -425,7 +631,7 @@ OO.ui.ActionSet.prototype.get = function ( filters ) {
}
// Remove duplicates
for ( i = 0, len = matches.length; i < len; i++ ) {
- match = matches[i];
+ match = matches[ i ];
index = matches.lastIndexOf( match );
while ( index !== i ) {
matches.splice( index, 1 );
@@ -439,12 +645,12 @@ OO.ui.ActionSet.prototype.get = function ( filters ) {
};
/**
- * Get special actions.
+ * Get 'special' actions.
*
- * Special actions are the first visible actions with special flags, such as 'safe' and 'primary'.
- * Special flags can be configured by changing #static-specialFlags in a subclass.
+ * Special actions are the first visible action widgets with special flags, such as 'safe' and 'primary'.
+ * Special flags can be configured in subclasses by changing the static #specialFlags property.
*
- * @return {OO.ui.ActionWidget|null} Safe action
+ * @return {OO.ui.ActionWidget[]|null} 'Special' action widgets.
*/
OO.ui.ActionSet.prototype.getSpecial = function () {
this.organize();
@@ -452,11 +658,11 @@ OO.ui.ActionSet.prototype.getSpecial = function () {
};
/**
- * Get other actions.
+ * Get 'other' actions.
*
- * Other actions include all non-special visible actions.
+ * Other actions include all non-special visible action widgets.
*
- * @return {OO.ui.ActionWidget[]} Other actions
+ * @return {OO.ui.ActionWidget[]} 'Other' action widgets
*/
OO.ui.ActionSet.prototype.getOthers = function () {
this.organize();
@@ -464,12 +670,11 @@ OO.ui.ActionSet.prototype.getOthers = function () {
};
/**
- * Toggle actions based on their modes.
- *
- * Unlike calling toggle on actions with matching flags, this will enforce mutually exclusive
- * visibility; matching actions will be shown, non-matching actions will be hidden.
+ * Set the mode (e.g., ‘edit’ or ‘view’). Only {@link OO.ui.ActionWidget#modes actions} configured
+ * to be available in the specified mode will be made visible. All other actions will be hidden.
*
- * @param {string} mode Mode actions must have
+ * @param {string} mode The mode. Only actions configured to be available in the specified
+ * mode will be made visible.
* @chainable
* @fires toggle
* @fires change
@@ -479,7 +684,7 @@ OO.ui.ActionSet.prototype.setMode = function ( mode ) {
this.changing = true;
for ( i = 0, len = this.list.length; i < len; i++ ) {
- action = this.list[i];
+ action = this.list[ i ];
action.toggle( action.hasMode( mode ) );
}
@@ -491,22 +696,24 @@ OO.ui.ActionSet.prototype.setMode = function ( mode ) {
};
/**
- * Change which actions are able to be performed.
+ * Set the abilities of the specified actions.
*
- * Actions with matching actions will be disabled/enabled. Other actions will not be changed.
+ * Action widgets that are configured with the specified actions will be enabled
+ * or disabled based on the boolean values specified in the `actions`
+ * parameter.
*
- * @param {Object.<string,boolean>} actions List of abilities, keyed by action name, values
- * indicate actions are able to be performed
+ * @param {Object.<string,boolean>} actions A list keyed by action name with boolean
+ * values that indicate whether or not the action should be enabled.
* @chainable
*/
OO.ui.ActionSet.prototype.setAbilities = function ( actions ) {
var i, len, action, item;
for ( i = 0, len = this.list.length; i < len; i++ ) {
- item = this.list[i];
+ item = this.list[ i ];
action = item.getAction();
- if ( actions[action] !== undefined ) {
- item.setDisabled( !actions[action] );
+ if ( actions[ action ] !== undefined ) {
+ item.setDisabled( !actions[ action ] );
}
}
@@ -517,9 +724,9 @@ OO.ui.ActionSet.prototype.setAbilities = function ( actions ) {
* Executes a function once per action.
*
* When making changes to multiple actions, use this method instead of iterating over the actions
- * manually to defer emitting a change event until after all actions have been changed.
+ * manually to defer emitting a #change event until after all actions have been changed.
*
- * @param {Object|null} actions Filters to use for which actions to iterate over; see #get
+ * @param {Object|null} actions Filters to use to determine which actions to iterate over; see #get
* @param {Function} callback Callback to run for each action; callback is invoked with three
* arguments: the action, the action's index, the list of actions being iterated over
* @chainable
@@ -537,9 +744,9 @@ OO.ui.ActionSet.prototype.forEach = function ( filter, callback ) {
};
/**
- * Add actions.
+ * Add action widgets to the action set.
*
- * @param {OO.ui.ActionWidget[]} actions Actions to add
+ * @param {OO.ui.ActionWidget[]} actions Action widgets to add
* @chainable
* @fires add
* @fires change
@@ -549,7 +756,7 @@ OO.ui.ActionSet.prototype.add = function ( actions ) {
this.changing = true;
for ( i = 0, len = actions.length; i < len; i++ ) {
- action = actions[i];
+ action = actions[ i ];
action.connect( this, {
click: [ 'emit', 'click', action ],
resize: [ 'emit', 'resize', action ],
@@ -566,9 +773,11 @@ OO.ui.ActionSet.prototype.add = function ( actions ) {
};
/**
- * Remove actions.
+ * Remove action widgets from the set.
+ *
+ * To remove all actions, you may wish to use the #clear method instead.
*
- * @param {OO.ui.ActionWidget[]} actions Actions to remove
+ * @param {OO.ui.ActionWidget[]} actions Action widgets to remove
* @chainable
* @fires remove
* @fires change
@@ -578,7 +787,7 @@ OO.ui.ActionSet.prototype.remove = function ( actions ) {
this.changing = true;
for ( i = 0, len = actions.length; i < len; i++ ) {
- action = actions[i];
+ action = actions[ i ];
index = this.list.indexOf( action );
if ( index !== -1 ) {
action.disconnect( this );
@@ -594,7 +803,9 @@ OO.ui.ActionSet.prototype.remove = function ( actions ) {
};
/**
- * Remove all actions.
+ * Remove all action widets from the set.
+ *
+ * To remove only specified actions, use the {@link #method-remove remove} method instead.
*
* @chainable
* @fires remove
@@ -606,7 +817,7 @@ OO.ui.ActionSet.prototype.clear = function () {
this.changing = true;
for ( i = 0, len = this.list.length; i < len; i++ ) {
- action = this.list[i];
+ action = this.list[ i ];
action.disconnect( this );
}
@@ -623,7 +834,7 @@ OO.ui.ActionSet.prototype.clear = function () {
/**
* Organize actions.
*
- * This is called whenver organized information is requested. It will only reorganize the actions
+ * This is called whenever organized information is requested. It will only reorganize the actions
* if something has changed since the last time it ran.
*
* @private
@@ -638,31 +849,31 @@ OO.ui.ActionSet.prototype.organize = function () {
this.special = {};
this.others = [];
for ( i = 0, iLen = this.list.length; i < iLen; i++ ) {
- action = this.list[i];
+ action = this.list[ i ];
if ( action.isVisible() ) {
- // Populate catgeories
+ // Populate categories
for ( category in this.categories ) {
- if ( !this.categorized[category] ) {
- this.categorized[category] = {};
+ if ( !this.categorized[ category ] ) {
+ this.categorized[ category ] = {};
}
- list = action[this.categories[category]]();
+ list = action[ this.categories[ category ] ]();
if ( !Array.isArray( list ) ) {
list = [ list ];
}
for ( j = 0, jLen = list.length; j < jLen; j++ ) {
- item = list[j];
- if ( !this.categorized[category][item] ) {
- this.categorized[category][item] = [];
+ item = list[ j ];
+ if ( !this.categorized[ category ][ item ] ) {
+ this.categorized[ category ][ item ] = [];
}
- this.categorized[category][item].push( action );
+ this.categorized[ category ][ item ].push( action );
}
}
// Populate special/others
special = false;
for ( j = 0, jLen = specialFlags.length; j < jLen; j++ ) {
- flag = specialFlags[j];
- if ( !this.special[flag] && action.hasFlag( flag ) ) {
- this.special[flag] = action;
+ flag = specialFlags[ j ];
+ if ( !this.special[ flag ] && action.hasFlag( flag ) ) {
+ this.special[ flag ] = action;
special = true;
break;
}
@@ -679,35 +890,71 @@ OO.ui.ActionSet.prototype.organize = function () {
};
/**
- * DOM element abstraction.
+ * Each Element represents a rendering in the DOM—a button or an icon, for example, or anything
+ * that is visible to a user. Unlike {@link OO.ui.Widget widgets}, plain elements usually do not have events
+ * connected to them and can't be interacted with.
*
* @abstract
* @class
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {Function} [$] jQuery for the frame the widget is in
- * @cfg {string[]} [classes] CSS class names
+ * @cfg {string[]} [classes] The names of the CSS classes to apply to the element. CSS styles are added
+ * to the top level (e.g., the outermost div) of the element. See the [OOjs UI documentation on MediaWiki][2]
+ * for an example.
+ * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Buttons_and_Switches#cssExample
+ * @cfg {string} [id] The HTML id attribute used in the rendered tag.
* @cfg {string} [text] Text to insert
- * @cfg {jQuery} [$content] Content elements to append (after text)
+ * @cfg {Array} [content] An array of content elements to append (after #text).
+ * Strings will be html-escaped; use an OO.ui.HtmlSnippet to append raw HTML.
+ * Instances of OO.ui.Element will have their $element appended.
+ * @cfg {jQuery} [$content] Content elements to append (after #text)
+ * @cfg {Mixed} [data] Custom data of any type or combination of types (e.g., string, number, array, object).
+ * Data can also be specified with the #setData method.
*/
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.$ = $;
+ this.visible = true;
+ this.data = config.data;
+ this.$element = config.$element ||
+ $( document.createElement( this.getTagName() ) );
this.elementGroup = null;
+ this.debouncedUpdateThemeClassesHandler = this.debouncedUpdateThemeClasses.bind( this );
+ this.updateThemeClassesPending = false;
// Initialization
- if ( $.isArray( config.classes ) ) {
+ if ( Array.isArray( config.classes ) ) {
this.$element.addClass( config.classes.join( ' ' ) );
}
+ if ( config.id ) {
+ this.$element.attr( 'id', config.id );
+ }
if ( config.text ) {
this.$element.text( config.text );
}
+ if ( config.content ) {
+ // The `content` property treats plain strings as text; use an
+ // HtmlSnippet to append HTML content. `OO.ui.Element`s get their
+ // appropriate $element appended.
+ this.$element.append( config.content.map( function ( v ) {
+ if ( typeof v === 'string' ) {
+ // Escape string so it is properly represented in HTML.
+ return document.createTextNode( v );
+ } else if ( v instanceof OO.ui.HtmlSnippet ) {
+ // Bypass escaping.
+ return v.toString();
+ } else if ( v instanceof OO.ui.Element ) {
+ return v.$element;
+ }
+ return v;
+ } ) );
+ }
if ( config.$content ) {
+ // The `$content` property treats plain strings as HTML.
this.$element.append( config.$content );
}
};
@@ -719,9 +966,9 @@ OO.initClass( OO.ui.Element );
/* Static Properties */
/**
- * HTML tag name.
+ * The name of the HTML tag used by the element.
*
- * This may be ignored if getTagName is overridden.
+ * The static value may be ignored if the #getTagName method is overridden.
*
* @static
* @inheritable
@@ -732,6 +979,103 @@ OO.ui.Element.static.tagName = 'div';
/* Static Methods */
/**
+ * Reconstitute a JavaScript object corresponding to a widget created
+ * by the PHP implementation.
+ *
+ * @param {string|HTMLElement|jQuery} idOrNode
+ * A DOM id (if a string) or node for the widget to infuse.
+ * @return {OO.ui.Element}
+ * The `OO.ui.Element` corresponding to this (infusable) document node.
+ * For `Tag` objects emitted on the HTML side (used occasionally for content)
+ * the value returned is a newly-created Element wrapping around the existing
+ * DOM node.
+ */
+OO.ui.Element.static.infuse = function ( idOrNode ) {
+ var obj = OO.ui.Element.static.unsafeInfuse( idOrNode, true );
+ // Verify that the type matches up.
+ // FIXME: uncomment after T89721 is fixed (see T90929)
+ /*
+ if ( !( obj instanceof this['class'] ) ) {
+ throw new Error( 'Infusion type mismatch!' );
+ }
+ */
+ return obj;
+};
+
+/**
+ * Implementation helper for `infuse`; skips the type check and has an
+ * extra property so that only the top-level invocation touches the DOM.
+ * @private
+ * @param {string|HTMLElement|jQuery} idOrNode
+ * @param {boolean} top True only for top-level invocation.
+ * @return {OO.ui.Element}
+ */
+OO.ui.Element.static.unsafeInfuse = function ( idOrNode, top ) {
+ // look for a cached result of a previous infusion.
+ var id, $elem, data, cls, obj;
+ if ( typeof idOrNode === 'string' ) {
+ id = idOrNode;
+ $elem = $( document.getElementById( id ) );
+ } else {
+ $elem = $( idOrNode );
+ id = $elem.attr( 'id' );
+ }
+ data = $elem.data( 'ooui-infused' );
+ if ( data ) {
+ // cached!
+ if ( data === true ) {
+ throw new Error( 'Circular dependency! ' + id );
+ }
+ return data;
+ }
+ if ( !$elem.length ) {
+ throw new Error( 'Widget not found: ' + id );
+ }
+ data = $elem.attr( 'data-ooui' );
+ if ( !data ) {
+ throw new Error( 'No infusion data found: ' + id );
+ }
+ try {
+ data = $.parseJSON( data );
+ } catch ( _ ) {
+ data = null;
+ }
+ if ( !( data && data._ ) ) {
+ throw new Error( 'No valid infusion data found: ' + id );
+ }
+ if ( data._ === 'Tag' ) {
+ // Special case: this is a raw Tag; wrap existing node, don't rebuild.
+ return new OO.ui.Element( { $element: $elem } );
+ }
+ cls = OO.ui[data._];
+ if ( !cls ) {
+ throw new Error( 'Unknown widget type: ' + id );
+ }
+ $elem.data( 'ooui-infused', true ); // prevent loops
+ data.id = id; // implicit
+ data = OO.copy( data, null, function deserialize( value ) {
+ if ( OO.isPlainObject( value ) ) {
+ if ( value.tag ) {
+ return OO.ui.Element.static.unsafeInfuse( value.tag, false );
+ }
+ if ( value.html ) {
+ return new OO.ui.HtmlSnippet( value.html );
+ }
+ }
+ } );
+ // jscs:disable requireCapitalizedConstructors
+ obj = new cls( data ); // rebuild widget
+ // now replace old DOM with this new DOM.
+ if ( top ) {
+ $elem.replaceWith( obj.$element );
+ }
+ obj.$element.data( 'ooui-infused', obj );
+ // set the 'data-ooui' attribute so we can identify infused widgets
+ obj.$element.attr( 'data-ooui', '' );
+ return obj;
+};
+
+/**
* Get a jQuery function within a specific document.
*
* @static
@@ -740,7 +1084,7 @@ OO.ui.Element.static.tagName = 'div';
* not in an iframe
* @return {Function} Bound jQuery function
*/
-OO.ui.Element.getJQuery = function ( context, $iframe ) {
+OO.ui.Element.static.getJQuery = function ( context, $iframe ) {
function wrapper( selector ) {
return $( selector, wrapper.context );
}
@@ -761,9 +1105,9 @@ OO.ui.Element.getJQuery = function ( context, $iframe ) {
* @param {jQuery|HTMLElement|HTMLDocument|Window} obj Object to get the document for
* @return {HTMLDocument|null} Document object
*/
-OO.ui.Element.getDocument = function ( obj ) {
+OO.ui.Element.static.getDocument = function ( obj ) {
// jQuery - selections created "offscreen" won't have a context, so .context isn't reliable
- return ( obj[0] && obj[0].ownerDocument ) ||
+ return ( obj[ 0 ] && obj[ 0 ].ownerDocument ) ||
// Empty jQuery selections might have a context
obj.context ||
// HTMLElement
@@ -782,7 +1126,7 @@ OO.ui.Element.getDocument = function ( obj ) {
* @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the window for
* @return {Window} Window object
*/
-OO.ui.Element.getWindow = function ( obj ) {
+OO.ui.Element.static.getWindow = function ( obj ) {
var doc = this.getDocument( obj );
return doc.parentWindow || doc.defaultView;
};
@@ -792,13 +1136,13 @@ OO.ui.Element.getWindow = function ( obj ) {
*
* @static
* @param {jQuery|HTMLElement|HTMLDocument|Window} obj Context to get the direction for
- * @return {string} Text direction, either `ltr` or `rtl`
+ * @return {string} Text direction, either 'ltr' or 'rtl'
*/
-OO.ui.Element.getDir = function ( obj ) {
+OO.ui.Element.static.getDir = function ( obj ) {
var isDoc, isWin;
if ( obj instanceof jQuery ) {
- obj = obj[0];
+ obj = obj[ 0 ];
}
isDoc = obj.nodeType === 9;
isWin = obj.document !== undefined;
@@ -822,7 +1166,7 @@ OO.ui.Element.getDir = function ( obj ) {
* @param {Object} [offset] Offset to start with, used internally
* @return {Object} Offset object, containing left and top properties
*/
-OO.ui.Element.getFrameOffset = function ( from, to, offset ) {
+OO.ui.Element.static.getFrameOffset = function ( from, to, offset ) {
var i, len, frames, frame, rect;
if ( !to ) {
@@ -838,8 +1182,8 @@ OO.ui.Element.getFrameOffset = function ( from, to, 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];
+ if ( frames[ i ].contentWindow === from ) {
+ frame = frames[ i ];
break;
}
}
@@ -859,15 +1203,35 @@ OO.ui.Element.getFrameOffset = function ( from, to, offset ) {
/**
* Get the offset between two elements.
*
+ * The two elements may be in a different frame, but in that case the frame $element is in must
+ * be contained in the frame $anchor is in.
+ *
* @static
- * @param {jQuery} $from
- * @param {jQuery} $to
+ * @param {jQuery} $element Element whose position to get
+ * @param {jQuery} $anchor Element to get $element's position relative to
* @return {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 ) };
+OO.ui.Element.static.getRelativePosition = function ( $element, $anchor ) {
+ var iframe, iframePos,
+ pos = $element.offset(),
+ anchorPos = $anchor.offset(),
+ elementDocument = this.getDocument( $element ),
+ anchorDocument = this.getDocument( $anchor );
+
+ // If $element isn't in the same document as $anchor, traverse up
+ while ( elementDocument !== anchorDocument ) {
+ iframe = elementDocument.defaultView.frameElement;
+ if ( !iframe ) {
+ throw new Error( '$element frame is not contained in $anchor frame' );
+ }
+ iframePos = $( iframe ).offset();
+ pos.left += iframePos.left;
+ pos.top += iframePos.top;
+ elementDocument = iframe.ownerDocument;
+ }
+ pos.left -= anchorPos.left;
+ pos.top -= anchorPos.top;
+ return pos;
};
/**
@@ -877,7 +1241,7 @@ OO.ui.Element.getRelativePosition = function ( $from, $to ) {
* @param {HTMLElement} el Element to measure
* @return {Object} Dimensions object with `top`, `left`, `bottom` and `right` properties
*/
-OO.ui.Element.getBorders = function ( el ) {
+OO.ui.Element.static.getBorders = function ( el ) {
var doc = el.ownerDocument,
win = doc.parentWindow || doc.defaultView,
style = win && win.getComputedStyle ?
@@ -890,10 +1254,10 @@ OO.ui.Element.getBorders = function ( el ) {
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 )
+ top: top,
+ left: left,
+ bottom: bottom,
+ right: right
};
};
@@ -904,7 +1268,7 @@ OO.ui.Element.getBorders = function ( el ) {
* @param {HTMLElement|Window} el Element to measure
* @return {Object} Dimensions object with `borders`, `scroll`, `scrollbar` and `rect` properties
*/
-OO.ui.Element.getDimensions = function ( el ) {
+OO.ui.Element.static.getDimensions = function ( el ) {
var $el, $win,
doc = el.ownerDocument || el.document,
win = doc.parentWindow || doc.defaultView;
@@ -943,6 +1307,38 @@ OO.ui.Element.getDimensions = function ( el ) {
};
/**
+ * Get scrollable object parent
+ *
+ * documentElement can't be used to get or set the scrollTop
+ * property on Blink. Changing and testing its value lets us
+ * use 'body' or 'documentElement' based on what is working.
+ *
+ * https://code.google.com/p/chromium/issues/detail?id=303131
+ *
+ * @static
+ * @param {HTMLElement} el Element to find scrollable parent for
+ * @return {HTMLElement} Scrollable parent
+ */
+OO.ui.Element.static.getRootScrollableElement = function ( el ) {
+ var scrollTop, body;
+
+ if ( OO.ui.scrollableElement === undefined ) {
+ body = el.ownerDocument.body;
+ scrollTop = body.scrollTop;
+ body.scrollTop = 1;
+
+ if ( body.scrollTop === 1 ) {
+ body.scrollTop = scrollTop;
+ OO.ui.scrollableElement = 'body';
+ } else {
+ OO.ui.scrollableElement = 'documentElement';
+ }
+ }
+
+ return el.ownerDocument[ OO.ui.scrollableElement ];
+};
+
+/**
* Get closest scrollable container.
*
* Traverses up until either a scrollable element or the root is reached, in which case the window
@@ -953,7 +1349,7 @@ OO.ui.Element.getDimensions = function ( el ) {
* @param {string} [dimension] Dimension of scrolling to look for; `x`, `y` or omit for either
* @return {HTMLElement} Closest scrollable container
*/
-OO.ui.Element.getClosestScrollableContainer = function ( el, dimension ) {
+OO.ui.Element.static.getClosestScrollableContainer = function ( el, dimension ) {
var i, val,
props = [ 'overflow' ],
$parent = $( el ).parent();
@@ -963,14 +1359,14 @@ OO.ui.Element.getClosestScrollableContainer = function ( el, dimension ) {
}
while ( $parent.length ) {
- if ( $parent[0] === el.ownerDocument.body ) {
- return $parent[0];
+ if ( $parent[ 0 ] === this.getRootScrollableElement( el ) ) {
+ return $parent[ 0 ];
}
i = props.length;
while ( i-- ) {
- val = $parent.css( props[i] );
+ val = $parent.css( props[ i ] );
if ( val === 'auto' || val === 'scroll' ) {
- return $parent[0];
+ return $parent[ 0 ];
}
}
$parent = $parent.parent();
@@ -983,13 +1379,13 @@ OO.ui.Element.getClosestScrollableContainer = function ( el, dimension ) {
*
* @static
* @param {HTMLElement} el Element to scroll into view
- * @param {Object} [config={}] Configuration config
+ * @param {Object} [config] Configuration options
* @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 ) {
+OO.ui.Element.static.scrollIntoView = function ( el, config ) {
// Configuration initialization
config = config || {};
@@ -1002,8 +1398,8 @@ OO.ui.Element.scrollIntoView = function ( el, config ) {
$win = $( this.getWindow( el ) );
// Compute the distances between the edges of el and the edges of the scroll viewport
- if ( $sc.is( 'body' ) ) {
- // If the scrollable container is the <body> this is easy
+ if ( $sc.is( 'html, body' ) ) {
+ // If the scrollable container is the root, this is easy
rel = {
top: eld.rect.top,
bottom: $win.innerHeight() - eld.rect.bottom,
@@ -1049,9 +1445,126 @@ OO.ui.Element.scrollIntoView = function ( el, config ) {
}
};
+/**
+ * Force the browser to reconsider whether it really needs to render scrollbars inside the element
+ * and reserve space for them, because it probably doesn't.
+ *
+ * Workaround primarily for <https://code.google.com/p/chromium/issues/detail?id=387290>, but also
+ * similar bugs in other browsers. "Just" forcing a reflow is not sufficient in all cases, we need
+ * to first actually detach (or hide, but detaching is simpler) all children, *then* force a reflow,
+ * and then reattach (or show) them back.
+ *
+ * @static
+ * @param {HTMLElement} el Element to reconsider the scrollbars on
+ */
+OO.ui.Element.static.reconsiderScrollbars = function ( el ) {
+ var i, len, nodes = [];
+ // Detach all children
+ while ( el.firstChild ) {
+ nodes.push( el.firstChild );
+ el.removeChild( el.firstChild );
+ }
+ // Force reflow
+ void el.offsetHeight;
+ // Reattach all children
+ for ( i = 0, len = nodes.length; i < len; i++ ) {
+ el.appendChild( nodes[ i ] );
+ }
+};
+
/* Methods */
/**
+ * Toggle visibility of an element.
+ *
+ * @param {boolean} [show] Make element visible, omit to toggle visibility
+ * @fires visible
+ * @chainable
+ */
+OO.ui.Element.prototype.toggle = function ( show ) {
+ show = show === undefined ? !this.visible : !!show;
+
+ if ( show !== this.isVisible() ) {
+ this.visible = show;
+ this.$element.toggleClass( 'oo-ui-element-hidden', !this.visible );
+ this.emit( 'toggle', show );
+ }
+
+ return this;
+};
+
+/**
+ * Check if element is visible.
+ *
+ * @return {boolean} element is visible
+ */
+OO.ui.Element.prototype.isVisible = function () {
+ return this.visible;
+};
+
+/**
+ * Get element data.
+ *
+ * @return {Mixed} Element data
+ */
+OO.ui.Element.prototype.getData = function () {
+ return this.data;
+};
+
+/**
+ * Set element data.
+ *
+ * @param {Mixed} Element data
+ * @chainable
+ */
+OO.ui.Element.prototype.setData = function ( data ) {
+ this.data = data;
+ return this;
+};
+
+/**
+ * Check if element supports one or more methods.
+ *
+ * @param {string|string[]} methods Method or list of methods to check
+ * @return {boolean} All methods are supported
+ */
+OO.ui.Element.prototype.supports = function ( methods ) {
+ var i, len,
+ support = 0;
+
+ methods = Array.isArray( methods ) ? methods : [ methods ];
+ for ( i = 0, len = methods.length; i < len; i++ ) {
+ if ( $.isFunction( this[ methods[ i ] ] ) ) {
+ support++;
+ }
+ }
+
+ return methods.length === support;
+};
+
+/**
+ * Update the theme-provided classes.
+ *
+ * @localdoc This is called in element mixins and widget classes any time state changes.
+ * Updating is debounced, minimizing overhead of changing multiple attributes and
+ * guaranteeing that theme updates do not occur within an element's constructor
+ */
+OO.ui.Element.prototype.updateThemeClasses = function () {
+ if ( !this.updateThemeClassesPending ) {
+ this.updateThemeClassesPending = true;
+ setTimeout( this.debouncedUpdateThemeClassesHandler );
+ }
+};
+
+/**
+ * @private
+ */
+OO.ui.Element.prototype.debouncedUpdateThemeClasses = function () {
+ OO.ui.theme.updateElementClasses( this );
+ this.updateThemeClassesPending = false;
+};
+
+/**
* Get the HTML tag name.
*
* Override this method to base the result on instance information.
@@ -1067,7 +1580,7 @@ OO.ui.Element.prototype.getTagName = function () {
* @return {boolean} The element is attached to the DOM
*/
OO.ui.Element.prototype.isElementAttached = function () {
- return $.contains( this.getElementDocument(), this.$element[0] );
+ return $.contains( this.getElementDocument(), this.$element[ 0 ] );
};
/**
@@ -1076,7 +1589,8 @@ OO.ui.Element.prototype.isElementAttached = function () {
* @return {HTMLDocument} Document object
*/
OO.ui.Element.prototype.getElementDocument = function () {
- return OO.ui.Element.getDocument( this.$element );
+ // Don't cache this in other ways either because subclasses could can change this.$element
+ return OO.ui.Element.static.getDocument( this.$element );
};
/**
@@ -1085,14 +1599,14 @@ OO.ui.Element.prototype.getElementDocument = function () {
* @return {Window} Window object
*/
OO.ui.Element.prototype.getElementWindow = function () {
- return OO.ui.Element.getWindow( this.$element );
+ return OO.ui.Element.static.getWindow( this.$element );
};
/**
* Get closest scrollable container.
*/
OO.ui.Element.prototype.getClosestScrollableElementContainer = function () {
- return OO.ui.Element.getClosestScrollableContainer( this.$element[0] );
+ return OO.ui.Element.static.getClosestScrollableContainer( this.$element[ 0 ] );
};
/**
@@ -1118,67 +1632,18 @@ OO.ui.Element.prototype.setElementGroup = function ( group ) {
/**
* Scroll element into view.
*
- * @param {Object} [config={}]
+ * @param {Object} [config] Configuration options
*/
OO.ui.Element.prototype.scrollElementIntoView = function ( config ) {
- return OO.ui.Element.scrollIntoView( this.$element[0], config );
-};
-
-/**
- * Bind a handler for an event on this.$element
- *
- * @deprecated Use jQuery#on instead.
- * @param {string} event
- * @param {Function} callback
- */
-OO.ui.Element.prototype.onDOMEvent = function ( event, callback ) {
- OO.ui.Element.onDOMEvent( this.$element, event, callback );
-};
-
-/**
- * Unbind a handler bound with #offDOMEvent
- *
- * @deprecated Use jQuery#off instead.
- * @param {string} event
- * @param {Function} callback
- */
-OO.ui.Element.prototype.offDOMEvent = function ( event, callback ) {
- OO.ui.Element.offDOMEvent( this.$element, event, callback );
+ return OO.ui.Element.static.scrollIntoView( this.$element[ 0 ], config );
};
-( function () {
- /**
- * Bind a handler for an event on a DOM element.
- *
- * Used to be for working around a jQuery bug (jqbug.com/14180),
- * but obsolete as of jQuery 1.11.0.
- *
- * @static
- * @deprecated Use jQuery#on instead.
- * @param {HTMLElement|jQuery} el DOM element
- * @param {string} event Event to bind
- * @param {Function} callback Callback to call when the event fires
- */
- OO.ui.Element.onDOMEvent = function ( el, event, callback ) {
- $( el ).on( event, callback );
- };
-
- /**
- * Unbind a handler bound with #static-method-onDOMEvent.
- *
- * @deprecated Use jQuery#off instead.
- * @static
- * @param {HTMLElement|jQuery} el DOM element
- * @param {string} event Event to unbind
- * @param {Function} [callback] Callback to unbind
- */
- OO.ui.Element.offDOMEvent = function ( el, event, callback ) {
- $( el ).off( event, callback );
- };
-}() );
-
/**
- * Container for elements.
+ * Layouts are containers for elements and are used to arrange other widgets of arbitrary type in a way
+ * that is centrally controlled and can be updated dynamically. Layouts can be, and usually are, combined.
+ * See {@link OO.ui.FieldsetLayout FieldsetLayout}, {@link OO.ui.FieldLayout FieldLayout}, {@link OO.ui.FormLayout FormLayout},
+ * {@link OO.ui.PanelLayout PanelLayout}, {@link OO.ui.StackLayout StackLayout}, {@link OO.ui.PageLayout PageLayout},
+ * and {@link OO.ui.BookletLayout BookletLayout} for more information and examples.
*
* @abstract
* @class
@@ -1189,7 +1654,7 @@ OO.ui.Element.prototype.offDOMEvent = function ( event, callback ) {
* @param {Object} [config] Configuration options
*/
OO.ui.Layout = function OoUiLayout( config ) {
- // Initialize config
+ // Configuration initialization
config = config || {};
// Parent constructor
@@ -1208,7 +1673,9 @@ OO.inheritClass( OO.ui.Layout, OO.ui.Element );
OO.mixinClass( OO.ui.Layout, OO.EventEmitter );
/**
- * User interface control.
+ * Widgets are compositions of one or more OOjs UI elements that users can both view
+ * and interact with. All widgets can be configured and modified via a standard API,
+ * and their state can change dynamically according to a model.
*
* @abstract
* @class
@@ -1217,7 +1684,8 @@ OO.mixinClass( OO.ui.Layout, OO.EventEmitter );
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {boolean} [disabled=false] Disable
+ * @cfg {boolean} [disabled=false] Disable the widget. Disabled widgets cannot be used and their
+ * appearance reflects this state.
*/
OO.ui.Widget = function OoUiWidget( config ) {
// Initialize config
@@ -1230,7 +1698,6 @@ OO.ui.Widget = function OoUiWidget( config ) {
OO.EventEmitter.call( this );
// Properties
- this.visible = true;
this.disabled = null;
this.wasDisabled = null;
@@ -1248,11 +1715,17 @@ OO.mixinClass( OO.ui.Widget, OO.EventEmitter );
/**
* @event disable
+ *
+ * A 'disable' event is emitted when a widget is disabled.
+ *
* @param {boolean} disabled Widget is disabled
*/
/**
* @event toggle
+ *
+ * A 'toggle' event is emitted when the visibility of the widget changes.
+ *
* @param {boolean} visible Widget is visible
*/
@@ -1261,25 +1734,16 @@ OO.mixinClass( OO.ui.Widget, OO.EventEmitter );
/**
* Check if the widget is disabled.
*
- * @param {boolean} Button is disabled
+ * @return {boolean} Widget is disabled
*/
OO.ui.Widget.prototype.isDisabled = function () {
return this.disabled;
};
/**
- * Check if widget is visible.
- *
- * @return {boolean} Widget is visible
- */
-OO.ui.Widget.prototype.isVisible = function () {
- return this.visible;
-};
-
-/**
- * Set the disabled state of the widget.
+ * Set the 'disabled' state of the widget.
*
- * This should probably change the widgets' appearance and prevent it from being used.
+ * When a widget is disabled, it cannot be used and its appearance is updated to reflect this state.
*
* @param {boolean} disabled Disable widget
* @chainable
@@ -1292,7 +1756,9 @@ OO.ui.Widget.prototype.setDisabled = function ( disabled ) {
if ( isDisabled !== this.wasDisabled ) {
this.$element.toggleClass( 'oo-ui-widget-disabled', isDisabled );
this.$element.toggleClass( 'oo-ui-widget-enabled', !isDisabled );
+ this.$element.attr( 'aria-disabled', isDisabled.toString() );
this.emit( 'disable', isDisabled );
+ this.updateThemeClasses();
}
this.wasDisabled = isDisabled;
@@ -1300,25 +1766,6 @@ OO.ui.Widget.prototype.setDisabled = function ( disabled ) {
};
/**
- * Toggle visibility of widget.
- *
- * @param {boolean} [show] Make widget visible, omit to toggle visibility
- * @fires visible
- * @chainable
- */
-OO.ui.Widget.prototype.toggle = function ( show ) {
- show = show === undefined ? !this.visible : !!show;
-
- if ( show !== this.isVisible() ) {
- this.visible = show;
- this.$element.toggle( show );
- this.emit( 'toggle', show );
- }
-
- return this;
-};
-
-/**
* Update the disabled state, in case of changes in parent widget.
*
* @chainable
@@ -1329,45 +1776,49 @@ OO.ui.Widget.prototype.updateDisabled = function () {
};
/**
- * Container for elements in a child frame.
+ * A window is a container for elements that are in a child frame. They are used with
+ * a window manager (OO.ui.WindowManager), which is used to open and close the window and control
+ * its presentation. The size of a window is specified using a symbolic name (e.g., ‘small’, ‘medium’,
+ * ‘large’), which is interpreted by the window manager. If the requested size is not recognized,
+ * the window manager will choose a sensible fallback.
*
- * Use together with OO.ui.WindowManager.
+ * The lifecycle of a window has three primary stages (opening, opened, and closing) in which
+ * different processes are executed:
*
- * @abstract
- * @class
- * @extends OO.ui.Element
- * @mixins OO.EventEmitter
- *
- * When a window is opened, the setup and ready processes are executed. Similarly, the hold and
- * teardown processes are executed when the window is closed.
+ * **opening**: The opening stage begins when the window manager's {@link OO.ui.WindowManager#openWindow
+ * openWindow} or the window's {@link #open open} methods are used, and the window manager begins to open
+ * the window.
*
- * - {@link OO.ui.WindowManager#openWindow} or {@link #open} methods are used to start opening
- * - Window manager begins opening window
* - {@link #getSetupProcess} method is called and its result executed
* - {@link #getReadyProcess} method is called and its result executed
- * - Window is now open
*
- * - {@link OO.ui.WindowManager#closeWindow} or {@link #close} methods are used to start closing
- * - Window manager begins closing window
+ * **opened**: The window is now open
+ *
+ * **closing**: The closing stage begins when the window manager's
+ * {@link OO.ui.WindowManager#closeWindow closeWindow}
+ * or the window's {@link #close} methods are used, and the window manager begins to close the window.
+ *
* - {@link #getHoldProcess} method is called and its result executed
- * - {@link #getTeardownProcess} method is called and its result executed
- * - Window is now closed
+ * - {@link #getTeardownProcess} method is called and its result executed. The window is now closed
+ *
+ * Each of the window's processes (setup, ready, hold, and teardown) can be extended in subclasses
+ * by overriding the window's #getSetupProcess, #getReadyProcess, #getHoldProcess and #getTeardownProcess
+ * methods. Note that each {@link OO.ui.Process process} is executed in series, so asynchronous
+ * processing can complete. Always assume window processes are executed asynchronously.
*
- * Each process (setup, ready, hold and teardown) can be extended in subclasses by overriding
- * {@link #getSetupProcess}, {@link #getReadyProcess}, {@link #getHoldProcess} and
- * {@link #getTeardownProcess} respectively. Each process is executed in series, so asynchonous
- * processing can complete. Always assume window processes are executed asychronously. See
- * OO.ui.Process for more details about how to work with processes. Some events, as well as the
- * #open and #close methods, provide promises which are resolved when the window enters a new state.
+ * For more information, please see the [OOjs UI documentation on MediaWiki] [1].
*
- * Sizing of windows is specified using symbolic names which are interpreted by the window manager.
- * If the requested size is not recognized, the window manager will choose a sensible fallback.
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows
+ *
+ * @abstract
+ * @class
+ * @extends OO.ui.Element
+ * @mixins OO.EventEmitter
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {string} [size] Symbolic name of dialog size, `small`, `medium`, `large` or `full`; omit to
- * use #static-size
- * @fires initialize
+ * @cfg {string} [size] Symbolic name of the dialog size: `small`, `medium`, `large`, `larger` or
+ * `full`. If omitted, the value of the {@link #static-size static size} property will be used.
*/
OO.ui.Window = function OoUiWindow( config ) {
// Configuration initialization
@@ -1381,23 +1832,29 @@ OO.ui.Window = function OoUiWindow( config ) {
// Properties
this.manager = null;
- this.initialized = false;
- this.visible = false;
- this.opening = null;
- this.closing = null;
- this.opened = null;
- this.timing = null;
- this.loading = null;
this.size = config.size || this.constructor.static.size;
- this.$frame = this.$( '<div>' );
+ this.$frame = $( '<div>' );
+ this.$overlay = $( '<div>' );
+ this.$content = $( '<div>' );
// Initialization
+ this.$overlay.addClass( 'oo-ui-window-overlay' );
+ this.$content
+ .addClass( 'oo-ui-window-content' )
+ .attr( 'tabindex', 0 );
+ this.$frame
+ .addClass( 'oo-ui-window-frame' )
+ .append( this.$content );
+
this.$element
.addClass( 'oo-ui-window' )
- .append( this.$frame );
- this.$frame.addClass( 'oo-ui-window-frame' );
+ .append( this.$frame, this.$overlay );
- // NOTE: Additional intitialization will occur when #setManager is called
+ // Initially hidden - using #toggle may cause errors if subclasses override toggle with methods
+ // that reference properties not initialized at that time of parent class construction
+ // TODO: Find a better way to handle post-constructor setup
+ this.visible = false;
+ this.$element.addClass( 'oo-ui-element-hidden' );
};
/* Setup */
@@ -1405,19 +1862,12 @@ OO.ui.Window = function OoUiWindow( config ) {
OO.inheritClass( OO.ui.Window, OO.ui.Element );
OO.mixinClass( OO.ui.Window, OO.EventEmitter );
-/* Events */
-
-/**
- * @event resize
- * @param {string} size Symbolic size name, e.g. 'small', 'medium', 'large', 'full'
- */
-
/* Static Properties */
/**
- * Symbolic name of size.
+ * Symbolic name of the window size: `small`, `medium`, `large`, `larger` or `full`.
*
- * Size is used if no size is configured during construction.
+ * The static size is used if no #size is configured during construction.
*
* @static
* @inheritable
@@ -1425,143 +1875,34 @@ OO.mixinClass( OO.ui.Window, OO.EventEmitter );
*/
OO.ui.Window.static.size = 'medium';
-/* 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, resolves the promise.
- *
- * If the styles still haven't loaded after a long time (5 seconds by default), we give up waiting
- * and resolve the promise 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
- * @inheritable
- * @param {HTMLDocument} parentDoc Document to transplant styles from
- * @param {HTMLDocument} frameDoc Document to transplant styles to
- * @param {number} [timeout=5000] How long to wait before giving up (in ms). If 0, never give up.
- * @return {jQuery.Promise} Promise resolved when styles have loaded
- */
-OO.ui.Window.static.transplantStyles = function ( parentDoc, frameDoc, timeout ) {
- var i, numSheets, styleNode, styleText, newNode, timeoutID, pollNodeId, $pendingPollNodes,
- $pollNodes = $( [] ),
- // Fake font-family value
- fontFamily = 'oo-ui-frame-transplantStyles-loaded',
- nextIndex = parentDoc.oouiFrameTransplantStylesNextIndex || 0,
- deferred = $.Deferred();
-
- for ( i = 0, numSheets = parentDoc.styleSheets.length; i < numSheets; i++ ) {
- styleNode = parentDoc.styleSheets[i].ownerNode;
- if ( styleNode.disabled ) {
- continue;
- }
-
- if ( styleNode.nodeName.toLowerCase() === 'link' ) {
- // External stylesheet; use @import
- styleText = '@import url(' + styleNode.href + ');';
- } else {
- // Internal stylesheet; just copy the text
- // For IE10 we need to fall back to .cssText, BUT that's undefined in
- // other browsers, so fall back to '' rather than 'undefined'
- styleText = styleNode.textContent || parentDoc.styleSheets[i].cssText || '';
- }
-
- // Create a node with a unique ID that we're going to monitor to see when the CSS
- // has loaded
- if ( styleNode.oouiFrameTransplantStylesId ) {
- // If we're nesting transplantStyles operations and this node already has
- // a CSS rule to wait for loading, reuse it
- pollNodeId = styleNode.oouiFrameTransplantStylesId;
- } else {
- // Otherwise, create a new ID
- pollNodeId = 'oo-ui-frame-transplantStyles-loaded-' + nextIndex;
- nextIndex++;
-
- // Add #pollNodeId { font-family: ... } to the end of the stylesheet / after the @import
- // The font-family rule will only take effect once the @import finishes
- styleText += '\n' + '#' + pollNodeId + ' { font-family: ' + fontFamily + '; }';
- }
-
- // Create a node with id=pollNodeId
- $pollNodes = $pollNodes.add( $( '<div>', frameDoc )
- .attr( 'id', pollNodeId )
- .appendTo( frameDoc.body )
- );
-
- // Add our modified CSS as a <style> tag
- newNode = frameDoc.createElement( 'style' );
- newNode.textContent = styleText;
- newNode.oouiFrameTransplantStylesId = pollNodeId;
- frameDoc.head.appendChild( newNode );
- }
- frameDoc.oouiFrameTransplantStylesNextIndex = nextIndex;
-
- // 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();
- deferred.resolve();
- }
- } 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();
- deferred.reject();
- }
- }, timeout || 5000 );
- }
-
- return deferred.promise();
-};
-
/* Methods */
/**
* Handle mouse down events.
*
+ * @private
* @param {jQuery.Event} e Mouse down event
*/
OO.ui.Window.prototype.onMouseDown = function ( e ) {
// Prevent clicking on the click-block from stealing focus
- if ( e.target === this.$element[0] ) {
+ if ( e.target === this.$element[ 0 ] ) {
return false;
}
};
/**
- * Check if window has been initialized.
+ * Check if the window has been initialized.
+ *
+ * Initialization occurs when a window is added to a manager.
*
* @return {boolean} Window has been initialized
*/
OO.ui.Window.prototype.isInitialized = function () {
- return this.initialized;
+ return !!this.manager;
};
/**
- * Check if window is visible.
+ * Check if the window is visible.
*
* @return {boolean} Window is visible
*/
@@ -1570,27 +1911,10 @@ OO.ui.Window.prototype.isVisible = function () {
};
/**
- * Check if window is loading.
- *
- * @return {boolean} Window is loading
- */
-OO.ui.Window.prototype.isLoading = function () {
- return this.loading && this.loading.state() === 'pending';
-};
-
-/**
- * Check if window is loaded.
+ * Check if the window is opening.
*
- * @return {boolean} Window is loaded
- */
-OO.ui.Window.prototype.isLoaded = function () {
- return this.loading && this.loading.state() === 'resolved';
-};
-
-/**
- * Check if window is opening.
- *
- * This is a wrapper around OO.ui.WindowManager#isOpening.
+ * This method is a wrapper around the window manager's {@link OO.ui.WindowManager#isOpening isOpening}
+ * method.
*
* @return {boolean} Window is opening
*/
@@ -1599,9 +1923,9 @@ OO.ui.Window.prototype.isOpening = function () {
};
/**
- * Check if window is closing.
+ * Check if the window is closing.
*
- * This is a wrapper around OO.ui.WindowManager#isClosing.
+ * This method is a wrapper around the window manager's {@link OO.ui.WindowManager#isClosing isClosing} method.
*
* @return {boolean} Window is closing
*/
@@ -1610,9 +1934,9 @@ OO.ui.Window.prototype.isClosing = function () {
};
/**
- * Check if window is opened.
+ * Check if the window is opened.
*
- * This is a wrapper around OO.ui.WindowManager#isOpened.
+ * This method is a wrapper around the window manager's {@link OO.ui.WindowManager#isOpened isOpened} method.
*
* @return {boolean} Window is opened
*/
@@ -1623,6 +1947,9 @@ OO.ui.Window.prototype.isOpened = function () {
/**
* Get the window manager.
*
+ * All windows must be attached to a window manager, which is used to open
+ * and close the window and control its presentation.
+ *
* @return {OO.ui.WindowManager} Manager of window
*/
OO.ui.Window.prototype.getManager = function () {
@@ -1630,27 +1957,69 @@ OO.ui.Window.prototype.getManager = function () {
};
/**
- * Get the window size.
+ * Get the symbolic name of the window size (e.g., `small` or `medium`).
*
- * @return {string} Symbolic size name, e.g. 'small', 'medium', 'large', 'full'
+ * @return {string} Symbolic name of the size: `small`, `medium`, `large`, `larger`, `full`
*/
OO.ui.Window.prototype.getSize = function () {
return this.size;
};
/**
- * Get the height of the dialog contents.
+ * Disable transitions on window's frame for the duration of the callback function, then enable them
+ * back.
*
- * @return {number} Content height
+ * @private
+ * @param {Function} callback Function to call while transitions are disabled
+ */
+OO.ui.Window.prototype.withoutSizeTransitions = function ( callback ) {
+ // Temporarily resize the frame so getBodyHeight() can use scrollHeight measurements.
+ // Disable transitions first, otherwise we'll get values from when the window was animating.
+ var oldTransition,
+ styleObj = this.$frame[ 0 ].style;
+ oldTransition = styleObj.transition || styleObj.OTransition || styleObj.MsTransition ||
+ styleObj.MozTransition || styleObj.WebkitTransition;
+ styleObj.transition = styleObj.OTransition = styleObj.MsTransition =
+ styleObj.MozTransition = styleObj.WebkitTransition = 'none';
+ callback();
+ // Force reflow to make sure the style changes done inside callback really are not transitioned
+ this.$frame.height();
+ styleObj.transition = styleObj.OTransition = styleObj.MsTransition =
+ styleObj.MozTransition = styleObj.WebkitTransition = oldTransition;
+};
+
+/**
+ * Get the height of the full window contents (i.e., the window head, body and foot together).
+ *
+ * What consistitutes the head, body, and foot varies depending on the window type.
+ * A {@link OO.ui.MessageDialog message dialog} displays a title and message in its body,
+ * and any actions in the foot. A {@link OO.ui.ProcessDialog process dialog} displays a title
+ * and special actions in the head, and dialog content in the body.
+ *
+ * To get just the height of the dialog body, use the #getBodyHeight method.
+ *
+ * @return {number} The height of the window contents (the dialog head, body and foot) in pixels
*/
OO.ui.Window.prototype.getContentHeight = function () {
- // Temporarily resize the frame so getBodyHeight() can use scrollHeight measurements
- var bodyHeight, oldHeight = this.$frame[0].style.height;
- this.$frame[0].style.height = '1px';
- bodyHeight = this.getBodyHeight();
- this.$frame[0].style.height = oldHeight;
+ var bodyHeight,
+ win = this,
+ bodyStyleObj = this.$body[ 0 ].style,
+ frameStyleObj = this.$frame[ 0 ].style;
+
+ // Temporarily resize the frame so getBodyHeight() can use scrollHeight measurements.
+ // Disable transitions first, otherwise we'll get values from when the window was animating.
+ this.withoutSizeTransitions( function () {
+ var oldHeight = frameStyleObj.height,
+ oldPosition = bodyStyleObj.position;
+ frameStyleObj.height = '1px';
+ // Force body to resize to new width
+ bodyStyleObj.position = 'relative';
+ bodyHeight = win.getBodyHeight();
+ frameStyleObj.height = oldHeight;
+ bodyStyleObj.position = oldPosition;
+ } );
- return Math.round(
+ return (
// Add buffer for border
( this.$frame.outerHeight() - this.$frame.innerHeight() ) +
// Use combined heights of children
@@ -1659,34 +2028,42 @@ OO.ui.Window.prototype.getContentHeight = function () {
};
/**
- * Get the height of the dialog contents.
+ * Get the height of the window body.
+ *
+ * To get the height of the full window contents (the window body, head, and foot together),
+ * use #getContentHeight.
*
- * When this function is called, the dialog will temporarily have been resized
+ * When this function is called, the window will temporarily have been resized
* to height=1px, so .scrollHeight measurements can be taken accurately.
*
- * @return {number} Height of content
+ * @return {number} Height of the window body in pixels
*/
OO.ui.Window.prototype.getBodyHeight = function () {
- return this.$body[0].scrollHeight;
+ return this.$body[ 0 ].scrollHeight;
};
/**
- * Get the directionality of the frame
+ * Get the directionality of the frame (right-to-left or left-to-right).
*
- * @return {string} Directionality, 'ltr' or 'rtl'
+ * @return {string} Directionality: `'ltr'` or `'rtl'`
*/
OO.ui.Window.prototype.getDir = function () {
return this.dir;
};
/**
- * Get a process for setting up a window for use.
+ * Get the 'setup' process.
*
- * Each time the window is opened this process will set it up for use in a particular context, based
- * on the `data` argument.
+ * The setup process is used to set up a window for use in a particular context,
+ * based on the `data` argument. This method is called during the opening phase of the window’s
+ * lifecycle.
*
- * When you override this method, you can add additional setup steps to the process the parent
- * method provides using the 'first' and 'next' methods.
+ * Override this method to add additional steps to the ‘setup’ process the parent method provides
+ * using the {@link OO.ui.Process#first first} and {@link OO.ui.Process#next next} methods
+ * of OO.ui.Process.
+ *
+ * To add window content that persists between openings, you may wish to use the #initialize method
+ * instead.
*
* @abstract
* @param {Object} [data] Window opening data
@@ -1697,30 +2074,34 @@ OO.ui.Window.prototype.getSetupProcess = function () {
};
/**
- * Get a process for readying a window for use.
+ * Get the ‘ready’ process.
*
- * Each time the window is open and setup, this process will ready it up for use in a particular
- * context, based on the `data` argument.
+ * The ready process is used to ready a window for use in a particular
+ * context, based on the `data` argument. This method is called during the opening phase of
+ * the window’s lifecycle, after the window has been {@link #getSetupProcess setup}.
*
- * When you override this method, you can add additional setup steps to the process the parent
- * method provides using the 'first' and 'next' methods.
+ * Override this method to add additional steps to the ‘ready’ process the parent method
+ * provides using the {@link OO.ui.Process#first first} and {@link OO.ui.Process#next next}
+ * methods of OO.ui.Process.
*
* @abstract
* @param {Object} [data] Window opening data
- * @return {OO.ui.Process} Setup process
+ * @return {OO.ui.Process} Ready process
*/
OO.ui.Window.prototype.getReadyProcess = function () {
return new OO.ui.Process();
};
/**
- * Get a process for holding a window from use.
+ * Get the 'hold' process.
*
- * Each time the window is closed, this process will hold it from use in a particular context, based
- * on the `data` argument.
+ * The hold proccess is used to keep a window from being used in a particular context,
+ * based on the `data` argument. This method is called during the closing phase of the window’s
+ * lifecycle.
*
- * When you override this method, you can add additional setup steps to the process the parent
- * method provides using the 'first' and 'next' methods.
+ * Override this method to add additional steps to the 'hold' process the parent method provides
+ * using the {@link OO.ui.Process#first first} and {@link OO.ui.Process#next next} methods
+ * of OO.ui.Process.
*
* @abstract
* @param {Object} [data] Window closing data
@@ -1731,13 +2112,15 @@ OO.ui.Window.prototype.getHoldProcess = function () {
};
/**
- * Get a process for tearing down a window after use.
+ * Get the ‘teardown’ process.
*
- * Each time the window is closed this process will tear it down and do something with the user's
- * interactions within the window, based on the `data` argument.
+ * The teardown process is used to teardown a window after use. During teardown,
+ * user interactions within the window are conveyed and the window is closed, based on the `data`
+ * argument. This method is called during the closing phase of the window’s lifecycle.
*
- * When you override this method, you can add additional teardown steps to the process the parent
- * method provides using the 'first' and 'next' methods.
+ * Override this method to add additional steps to the ‘teardown’ process the parent method provides
+ * using the {@link OO.ui.Process#first first} and {@link OO.ui.Process#next next} methods
+ * of OO.ui.Process.
*
* @abstract
* @param {Object} [data] Window closing data
@@ -1748,41 +2131,12 @@ OO.ui.Window.prototype.getTeardownProcess = function () {
};
/**
- * Toggle visibility of window.
- *
- * If the window is isolated and hasn't fully loaded yet, the visiblity property will be used
- * instead of display.
- *
- * @param {boolean} [show] Make window visible, omit to toggle visibility
- * @fires visible
- * @chainable
- */
-OO.ui.Window.prototype.toggle = function ( show ) {
- show = show === undefined ? !this.visible : !!show;
-
- if ( show !== this.isVisible() ) {
- this.visible = show;
-
- if ( this.isolated && !this.isLoaded() ) {
- // Hide the window using visibility instead of display until loading is complete
- // Can't use display: none; because that prevents the iframe from loading in Firefox
- this.$element.css( 'visibility', show ? 'visible' : 'hidden' );
- } else {
- this.$element.toggle( show ).css( 'visibility', '' );
- }
- this.emit( 'toggle', show );
- }
-
- return this;
-};
-
-/**
* Set the window manager.
*
- * This must be called before initialize. Calling it more than once will cause an error.
+ * This will cause the window to initialize. Calling it more than once will cause an error.
*
* @param {OO.ui.WindowManager} manager Manager for this window
- * @throws {Error} If called more than once
+ * @throws {Error} An error is thrown if the method is called more than once
* @chainable
*/
OO.ui.Window.prototype.setManager = function ( manager ) {
@@ -1790,49 +2144,46 @@ OO.ui.Window.prototype.setManager = function ( manager ) {
throw new Error( 'Cannot set window manager, window already has a manager' );
}
- // Properties
this.manager = manager;
- this.isolated = manager.shouldIsolate();
-
- // Initialization
- if ( this.isolated ) {
- this.$iframe = this.$( '<iframe>' );
- this.$iframe.attr( { frameborder: 0, scrolling: 'no' } );
- this.$frame.append( this.$iframe );
- this.$ = function () {
- throw new Error( 'this.$() cannot be used until the frame has been initialized.' );
- };
- // WARNING: Do not use this.$ again until #initialize is called
- } else {
- this.$content = this.$( '<div>' );
- this.$document = $( this.getElementDocument() );
- this.$content.addClass( 'oo-ui-window-content' );
- this.$frame.append( this.$content );
- }
- this.toggle( false );
-
- // Figure out directionality:
- this.dir = OO.ui.Element.getDir( this.$iframe || this.$content ) || 'ltr';
+ this.initialize();
return this;
};
/**
- * Set the window size.
+ * Set the window size by symbolic name (e.g., 'small' or 'medium')
*
- * @param {string} size Symbolic size name, e.g. 'small', 'medium', 'large', 'full'
+ * @param {string} size Symbolic name of size: `small`, `medium`, `large`, `larger` or
+ * `full`
* @chainable
*/
OO.ui.Window.prototype.setSize = function ( size ) {
this.size = size;
+ this.updateSize();
+ return this;
+};
+
+/**
+ * Update the window size.
+ *
+ * @throws {Error} An error is thrown if the window is not attached to a window manager
+ * @chainable
+ */
+OO.ui.Window.prototype.updateSize = function () {
+ if ( !this.manager ) {
+ throw new Error( 'Cannot update window size, must be attached to a manager' );
+ }
+
this.manager.updateWindowSize( this );
+
return this;
};
/**
- * Set window dimensions.
+ * Set window dimensions. This method is called by the {@link OO.ui.WindowManager window manager}
+ * when the window is opening. In general, setDimensions should not be called directly.
*
- * Properties are applied to the frame container.
+ * To set the size of the window, use the #setSize method.
*
* @param {Object} dim CSS dimension properties
* @param {string|number} [dim.width] Width
@@ -1844,29 +2195,43 @@ OO.ui.Window.prototype.setSize = function ( size ) {
* @chainable
*/
OO.ui.Window.prototype.setDimensions = function ( dim ) {
- // Apply width before height so height is not based on wrapping content using the wrong width
+ var height,
+ win = this,
+ styleObj = this.$frame[ 0 ].style;
+
+ // Calculate the height we need to set using the correct width
+ if ( dim.height === undefined ) {
+ this.withoutSizeTransitions( function () {
+ var oldWidth = styleObj.width;
+ win.$frame.css( 'width', dim.width || '' );
+ height = win.getContentHeight();
+ styleObj.width = oldWidth;
+ } );
+ } else {
+ height = dim.height;
+ }
+
this.$frame.css( {
width: dim.width || '',
minWidth: dim.minWidth || '',
- maxWidth: dim.maxWidth || ''
- } );
- this.$frame.css( {
- height: ( dim.height !== undefined ? dim.height : this.getContentHeight() ) || '',
+ maxWidth: dim.maxWidth || '',
+ height: height || '',
minHeight: dim.minHeight || '',
maxHeight: dim.maxHeight || ''
} );
+
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 #getSetupProcess for a way to make changes each time the window opens.
+ * Before the window is opened for the first time, #initialize is called so that content that
+ * persists between openings can be added to the window.
*
- * Once this method is called, this.$ can be used to create elements within the frame.
+ * To set up a window with new content each time the window opens, use #getSetupProcess.
*
- * @throws {Error} If not attached to a manager
+ * @throws {Error} An error is thrown if the window is not attached to a window manager
* @chainable
*/
OO.ui.Window.prototype.initialize = function () {
@@ -1875,55 +2240,73 @@ OO.ui.Window.prototype.initialize = function () {
}
// Properties
- this.$head = this.$( '<div>' );
- this.$body = this.$( '<div>' );
- this.$foot = this.$( '<div>' );
- this.$overlay = this.$( '<div>' );
+ this.$head = $( '<div>' );
+ this.$body = $( '<div>' );
+ this.$foot = $( '<div>' );
+ this.dir = OO.ui.Element.static.getDir( this.$content ) || 'ltr';
+ this.$document = $( this.getElementDocument() );
// Events
- this.$element.on( 'mousedown', OO.ui.bind( this.onMouseDown, this ) );
+ this.$element.on( 'mousedown', this.onMouseDown.bind( this ) );
// Initialization
this.$head.addClass( 'oo-ui-window-head' );
this.$body.addClass( 'oo-ui-window-body' );
this.$foot.addClass( 'oo-ui-window-foot' );
- this.$overlay.addClass( 'oo-ui-window-overlay' );
- this.$content.append( this.$head, this.$body, this.$foot, this.$overlay );
+ this.$content.append( this.$head, this.$body, this.$foot );
return this;
};
/**
- * Open window.
+ * Open the window.
*
- * This is a wrapper around calling {@link OO.ui.WindowManager#openWindow} on the window manager.
- * To do something each time the window opens, use #getSetupProcess or #getReadyProcess.
+ * This method is a wrapper around a call to the window manager’s {@link OO.ui.WindowManager#openWindow openWindow}
+ * method, which returns a promise resolved when the window is done opening.
+ *
+ * To customize the window each time it opens, use #getSetupProcess or #getReadyProcess.
*
* @param {Object} [data] Window opening data
- * @return {jQuery.Promise} Promise resolved when window is opened; when the promise is resolved the
- * first argument will be a promise which will be resolved when the window begins closing
+ * @return {jQuery.Promise} Promise resolved with a value when the window is opened, or rejected
+ * if the window fails to open. When the promise is resolved successfully, the first argument of the
+ * value is a new promise, which is resolved when the window begins closing.
+ * @throws {Error} An error is thrown if the window is not attached to a window manager
*/
OO.ui.Window.prototype.open = function ( data ) {
+ if ( !this.manager ) {
+ throw new Error( 'Cannot open window, must be attached to a manager' );
+ }
+
return this.manager.openWindow( this, data );
};
/**
- * Close window.
+ * Close the window.
+ *
+ * This method is a wrapper around a call to the window
+ * manager’s {@link OO.ui.WindowManager#closeWindow closeWindow} method,
+ * which returns a closing promise resolved when the window is done closing.
*
- * This is a wrapper around calling OO.ui.WindowManager#closeWindow on the window manager.
- * To do something each time the window closes, use #getHoldProcess or #getTeardownProcess.
+ * The window's #getHoldProcess and #getTeardownProcess methods are called during the closing
+ * phase of the window’s lifecycle and can be used to specify closing behavior each time
+ * the window closes.
*
* @param {Object} [data] Window closing data
* @return {jQuery.Promise} Promise resolved when window is closed
+ * @throws {Error} An error is thrown if the window is not attached to a window manager
*/
OO.ui.Window.prototype.close = function ( data ) {
+ if ( !this.manager ) {
+ throw new Error( 'Cannot close window, must be attached to a manager' );
+ }
+
return this.manager.closeWindow( this, data );
};
/**
* Setup window.
*
- * This is called by OO.ui.WindowManager durring window opening, and should not be called directly
+ * This is called by OO.ui.WindowManager during window opening, and should not be called directly
* by other systems.
*
* @param {Object} [data] Window opening data
@@ -1933,11 +2316,11 @@ OO.ui.Window.prototype.setup = function ( data ) {
var win = this,
deferred = $.Deferred();
- this.$element.show();
- this.visible = true;
+ this.toggle( true );
+
this.getSetupProcess( data ).execute().done( function () {
// Force redraw by asking the browser to measure the elements' widths
- win.$element.addClass( 'oo-ui-window-setup' ).width();
+ win.$element.addClass( 'oo-ui-window-active oo-ui-window-setup' ).width();
win.$content.addClass( 'oo-ui-window-content-setup' ).width();
deferred.resolve();
} );
@@ -1948,7 +2331,7 @@ OO.ui.Window.prototype.setup = function ( data ) {
/**
* Ready window.
*
- * This is called by OO.ui.WindowManager durring window opening, and should not be called directly
+ * This is called by OO.ui.WindowManager during window opening, and should not be called directly
* by other systems.
*
* @param {Object} [data] Window opening data
@@ -1972,7 +2355,7 @@ OO.ui.Window.prototype.ready = function ( data ) {
/**
* Hold window.
*
- * This is called by OO.ui.WindowManager durring window closing, and should not be called directly
+ * This is called by OO.ui.WindowManager during window closing, and should not be called directly
* by other systems.
*
* @param {Object} [data] Window closing data
@@ -1984,11 +2367,11 @@ OO.ui.Window.prototype.hold = function ( data ) {
this.getHoldProcess( data ).execute().done( function () {
// Get the focused element within the window's content
- var $focus = win.$content.find( OO.ui.Element.getDocument( win.$content ).activeElement );
+ var $focus = win.$content.find( OO.ui.Element.static.getDocument( win.$content ).activeElement );
// Blur the focused element
if ( $focus.length ) {
- $focus[0].blur();
+ $focus[ 0 ].blur();
}
// Force redraw by asking the browser to measure the elements' widths
@@ -2003,146 +2386,57 @@ OO.ui.Window.prototype.hold = function ( data ) {
/**
* Teardown window.
*
- * This is called by OO.ui.WindowManager durring window closing, and should not be called directly
+ * This is called by OO.ui.WindowManager during window closing, and should not be called directly
* by other systems.
*
* @param {Object} [data] Window closing data
* @return {jQuery.Promise} Promise resolved when window is torn down
*/
OO.ui.Window.prototype.teardown = function ( data ) {
- var win = this,
- deferred = $.Deferred();
-
- this.getTeardownProcess( data ).execute().done( function () {
- // Force redraw by asking the browser to measure the elements' widths
- win.$element.removeClass( 'oo-ui-window-setup' ).width();
- win.$content.removeClass( 'oo-ui-window-content-setup' ).width();
- win.$element.hide();
- win.visible = false;
- deferred.resolve();
- } );
-
- return deferred.promise();
-};
-
-/**
- * Load the frame contents.
- *
- * Once the iframe's stylesheets are loaded, the `load` event will be emitted and the returned
- * promise will be resolved. Calling while loading will return a promise but not trigger a new
- * loading cycle. Calling after loading is complete will return a promise that's already been
- * resolved.
- *
- * 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.
- *
- * @return {jQuery.Promise} Promise resolved when loading is complete
- * @fires load
- */
-OO.ui.Window.prototype.load = function () {
- var sub, doc, loading,
- win = this;
-
- // Non-isolated windows are already "loaded"
- if ( !this.loading && !this.isolated ) {
- this.loading = $.Deferred().resolve();
- this.initialize();
- // Set initialized state after so sub-classes aren't confused by it being set by calling
- // their parent initialize method
- this.initialized = true;
- }
-
- // Return existing promise if already loading or loaded
- if ( this.loading ) {
- return this.loading.promise();
- }
-
- // Load the frame
- loading = this.loading = $.Deferred();
- sub = this.$iframe.prop( 'contentWindow' );
- doc = sub.document;
-
- // Initialize contents
- doc.open();
- doc.write(
- '<!doctype html>' +
- '<html>' +
- '<body class="oo-ui-window-isolated oo-ui-' + this.dir + '"' +
- ' style="direction:' + this.dir + ';" dir="' + this.dir + '">' +
- '<div class="oo-ui-window-content"></div>' +
- '</body>' +
- '</html>'
- );
- doc.close();
-
- // Properties
- this.$ = OO.ui.Element.getJQuery( doc, this.$element );
- this.$content = this.$( '.oo-ui-window-content' ).attr( 'tabIndex', 0 );
- this.$document = this.$( doc );
-
- // Initialization
- this.constructor.static.transplantStyles( this.getElementDocument(), this.$document[0] )
- .always( function () {
- // Initialize isolated windows
- win.initialize();
- // Set initialized state after so sub-classes aren't confused by it being set by calling
- // their parent initialize method
- win.initialized = true;
- // Undo the visibility: hidden; hack and apply display: none;
- // We can do this safely now that the iframe has initialized
- // (don't do this from within #initialize because it has to happen
- // after the all subclasses have been handled as well).
- win.toggle( win.isVisible() );
-
- loading.resolve();
+ var win = this;
+
+ return this.getTeardownProcess( data ).execute()
+ .done( function () {
+ // Force redraw by asking the browser to measure the elements' widths
+ win.$element.removeClass( 'oo-ui-window-active oo-ui-window-setup' ).width();
+ win.$content.removeClass( 'oo-ui-window-content-setup' ).width();
+ win.toggle( false );
} );
-
- return loading.promise();
};
/**
- * Base class for all dialogs.
- *
- * Logic:
- * - Manage the window (open and close, etc.).
- * - Store the internal name and display title.
- * - A stack to track one or more pending actions.
- * - Manage a set of actions that can be performed.
- * - Configure and create action widgets.
- *
- * User interface:
- * - Close the dialog with Escape key.
- * - Visually lock the dialog while an action is in
- * progress (aka "pending").
- *
- * Subclass responsibilities:
- * - Display the title somewhere.
- * - Add content to the dialog.
- * - Provide a UI to close the dialog.
- * - Display the action widgets somewhere.
+ * The Dialog class serves as the base class for the other types of dialogs.
+ * Unless extended to include controls, the rendered dialog box is a simple window
+ * that users can close by hitting the ‘Esc’ key. Dialog windows are used with OO.ui.WindowManager,
+ * which opens, closes, and controls the presentation of the window. See the
+ * [OOjs UI documentation on MediaWiki] [1] for more information.
+ *
+ * @example
+ * // A simple dialog window.
+ * function MyDialog( config ) {
+ * MyDialog.super.call( this, config );
+ * }
+ * OO.inheritClass( MyDialog, OO.ui.Dialog );
+ * MyDialog.prototype.initialize = function () {
+ * MyDialog.super.prototype.initialize.call( this );
+ * this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );
+ * this.content.$element.append( '<p>A simple dialog window. Press \'Esc\' to close.</p>' );
+ * this.$body.append( this.content.$element );
+ * };
+ * MyDialog.prototype.getBodyHeight = function () {
+ * return this.content.$element.outerHeight( true );
+ * };
+ * var myDialog = new MyDialog( {
+ * size: 'medium'
+ * } );
+ * // Create and append a window manager, which opens and closes the window.
+ * var windowManager = new OO.ui.WindowManager();
+ * $( 'body' ).append( windowManager.$element );
+ * windowManager.addWindows( [ myDialog ] );
+ * // Open the window!
+ * windowManager.openWindow( myDialog );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Dialogs
*
* @abstract
* @class
@@ -2163,6 +2457,7 @@ OO.ui.Dialog = function OoUiDialog( config ) {
this.actions = new OO.ui.ActionSet();
this.attachedActions = [];
this.currentAction = null;
+ this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );
// Events
this.actions.connect( this, {
@@ -2187,6 +2482,11 @@ OO.mixinClass( OO.ui.Dialog, OO.ui.PendingElement );
/**
* Symbolic name of dialog.
*
+ * The dialog class must have a symbolic name in order to be registered with OO.Factory.
+ * Please see the [OOjs UI documentation on MediaWiki] [3] for more information.
+ *
+ * [3]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Window_managers
+ *
* @abstract
* @static
* @inheritable
@@ -2195,26 +2495,35 @@ OO.mixinClass( OO.ui.Dialog, OO.ui.PendingElement );
OO.ui.Dialog.static.name = '';
/**
- * Dialog title.
+ * The dialog title.
+ *
+ * The title can be specified as a plaintext string, a {@link OO.ui.LabelElement Label} node, or a function
+ * that will produce a Label node or string. The title can also be specified with data passed to the
+ * constructor (see #getSetupProcess). In this case, the static value will be overriden.
*
* @abstract
* @static
* @inheritable
- * @property {jQuery|string|Function} Label nodes, text or a function that returns nodes or text
+ * @property {jQuery|string|Function}
*/
OO.ui.Dialog.static.title = '';
/**
- * List of OO.ui.ActionWidget configuration options.
+ * An array of configured {@link OO.ui.ActionWidget action widgets}.
+ *
+ * Actions can also be specified with data passed to the constructor (see #getSetupProcess). In this case, the static
+ * value will be overriden.
+ *
+ * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Action_sets
*
* @static
- * inheritable
+ * @inheritable
* @property {Object[]}
*/
OO.ui.Dialog.static.actions = [];
/**
- * Close dialog when the escape key is pressed.
+ * Close the dialog when the 'Esc' key is pressed.
*
* @static
* @abstract
@@ -2228,18 +2537,21 @@ OO.ui.Dialog.static.escapable = true;
/**
* Handle frame document key down events.
*
+ * @private
* @param {jQuery.Event} e Key down event
*/
OO.ui.Dialog.prototype.onDocumentKeyDown = function ( e ) {
if ( e.which === OO.ui.Keys.ESCAPE ) {
this.close();
- return false;
+ e.preventDefault();
+ e.stopPropagation();
}
};
/**
* Handle action resized events.
*
+ * @private
* @param {OO.ui.ActionWidget} action Action that was resized
*/
OO.ui.Dialog.prototype.onActionResize = function () {
@@ -2249,17 +2561,19 @@ OO.ui.Dialog.prototype.onActionResize = function () {
/**
* Handle action click events.
*
+ * @private
* @param {OO.ui.ActionWidget} action Action that was clicked
*/
OO.ui.Dialog.prototype.onActionClick = function ( action ) {
if ( !this.isPending() ) {
- this.currentAction = action;
this.executeAction( action.getAction() );
}
};
/**
* Handle actions change event.
+ *
+ * @private
*/
OO.ui.Dialog.prototype.onActionsChange = function () {
this.detachActions();
@@ -2269,7 +2583,7 @@ OO.ui.Dialog.prototype.onActionsChange = function () {
};
/**
- * Get set of actions.
+ * Get the set of actions used by the dialog.
*
* @return {OO.ui.ActionSet}
*/
@@ -2280,8 +2594,9 @@ OO.ui.Dialog.prototype.getActions = function () {
/**
* Get a process for taking action.
*
- * When you override this method, you can add additional accept steps to the process the parent
- * method provides using the 'first' and 'next' methods.
+ * When you override this method, you can create a new OO.ui.Process and return it, or add additional
+ * accept steps to the process the parent method provides using the {@link OO.ui.Process#first 'first'}
+ * and {@link OO.ui.Process#next 'next'} methods of OO.ui.Process.
*
* @abstract
* @param {string} [action] Symbolic name of action
@@ -2302,9 +2617,10 @@ OO.ui.Dialog.prototype.getActionProcess = function ( action ) {
* @inheritdoc
*
* @param {Object} [data] Dialog opening data
- * @param {jQuery|string|Function|null} [data.title] Dialog title, omit to use #static-title
- * @param {Object[]} [data.actions] List of OO.ui.ActionWidget configuration options for each
- * action item, omit to use #static-actions
+ * @param {jQuery|string|Function|null} [data.title] Dialog title, omit to use
+ * the {@link #static-title static title}
+ * @param {Object[]} [data.actions] List of configuration options for each
+ * {@link OO.ui.ActionWidget action widget}, omit to use {@link #static-actions static actions}.
*/
OO.ui.Dialog.prototype.getSetupProcess = function ( data ) {
data = data || {};
@@ -2312,20 +2628,17 @@ OO.ui.Dialog.prototype.getSetupProcess = function ( data ) {
// Parent method
return OO.ui.Dialog.super.prototype.getSetupProcess.call( this, data )
.next( function () {
- var i, len,
- items = [],
- config = this.constructor.static,
+ var config = this.constructor.static,
actions = data.actions !== undefined ? data.actions : config.actions;
this.title.setLabel(
data.title !== undefined ? data.title : this.constructor.static.title
);
- for ( i = 0, len = actions.length; i < len; i++ ) {
- items.push(
- new OO.ui.ActionWidget( $.extend( { $: this.$ }, actions[i] ) )
- );
+ this.actions.add( this.getActionWidgets( actions ) );
+
+ if ( this.constructor.static.escapable ) {
+ this.$document.on( 'keydown', this.onDocumentKeyDownHandler );
}
- this.actions.add( items );
}, this );
};
@@ -2336,6 +2649,10 @@ OO.ui.Dialog.prototype.getTeardownProcess = function ( data ) {
// Parent method
return OO.ui.Dialog.super.prototype.getTeardownProcess.call( this, data )
.first( function () {
+ if ( this.constructor.static.escapable ) {
+ this.$document.off( 'keydown', this.onDocumentKeyDownHandler );
+ }
+
this.actions.clear();
this.currentAction = null;
}, this );
@@ -2349,12 +2666,7 @@ OO.ui.Dialog.prototype.initialize = function () {
OO.ui.Dialog.super.prototype.initialize.call( this );
// Properties
- this.title = new OO.ui.LabelWidget( { $: this.$ } );
-
- // Events
- if ( this.constructor.static.escapable ) {
- this.$document.on( 'keydown', OO.ui.bind( this.onDocumentKeyDown, this ) );
- }
+ this.title = new OO.ui.LabelWidget();
// Initialization
this.$content.addClass( 'oo-ui-dialog-content' );
@@ -2362,7 +2674,25 @@ OO.ui.Dialog.prototype.initialize = function () {
};
/**
+ * Get action widgets from a list of configs
+ *
+ * @param {Object[]} actions Action widget configs
+ * @return {OO.ui.ActionWidget[]} Action widgets
+ */
+OO.ui.Dialog.prototype.getActionWidgets = function ( actions ) {
+ var i, len, widgets = [];
+ for ( i = 0, len = actions.length; i < len; i++ ) {
+ widgets.push(
+ new OO.ui.ActionWidget( actions[ i ] )
+ );
+ }
+ return widgets;
+};
+
+/**
* Attach action actions.
+ *
+ * @protected
*/
OO.ui.Dialog.prototype.attachActions = function () {
// Remember the list of potentially attached actions
@@ -2372,6 +2702,7 @@ OO.ui.Dialog.prototype.attachActions = function () {
/**
* Detach action actions.
*
+ * @protected
* @chainable
*/
OO.ui.Dialog.prototype.detachActions = function () {
@@ -2379,7 +2710,7 @@ OO.ui.Dialog.prototype.detachActions = function () {
// Detach all actions that may have been previously attached
for ( i = 0, len = this.attachedActions.length; i < len; i++ ) {
- this.attachedActions[i].$element.detach();
+ this.attachedActions[ i ].$element.detach();
}
this.attachedActions = [];
};
@@ -2392,52 +2723,65 @@ OO.ui.Dialog.prototype.detachActions = function () {
*/
OO.ui.Dialog.prototype.executeAction = function ( action ) {
this.pushPending();
+ this.currentAction = action;
return this.getActionProcess( action ).execute()
- .always( OO.ui.bind( this.popPending, this ) );
+ .always( this.popPending.bind( this ) );
};
/**
- * Collection of windows.
+ * Window managers are used to open and close {@link OO.ui.Window windows} and control their presentation.
+ * Managed windows are mutually exclusive. If a new window is opened while a current window is opening
+ * or is opened, the current window will be closed and any ongoing {@link OO.ui.Process process} will be cancelled. Windows
+ * themselves are persistent and—rather than being torn down when closed—can be repopulated with the
+ * pertinent data and reused.
+ *
+ * Over the lifecycle of a window, the window manager makes available three promises: `opening`,
+ * `opened`, and `closing`, which represent the primary stages of the cycle:
+ *
+ * **Opening**: the opening stage begins when the window manager’s #openWindow or a window’s
+ * {@link OO.ui.Window#open open} method is used, and the window manager begins to open the window.
+ *
+ * - an `opening` event is emitted with an `opening` promise
+ * - the #getSetupDelay method is called and the returned value is used to time a pause in execution before
+ * the window’s {@link OO.ui.Window#getSetupProcess getSetupProcess} method is called on the
+ * window and its result executed
+ * - a `setup` progress notification is emitted from the `opening` promise
+ * - the #getReadyDelay method is called the returned value is used to time a pause in execution before
+ * the window’s {@link OO.ui.Window#getReadyProcess getReadyProcess} method is called on the
+ * window and its result executed
+ * - a `ready` progress notification is emitted from the `opening` promise
+ * - the `opening` promise is resolved with an `opened` promise
+ *
+ * **Opened**: the window is now open.
+ *
+ * **Closing**: the closing stage begins when the window manager's #closeWindow or the
+ * window's {@link OO.ui.Window#close close} methods is used, and the window manager begins
+ * to close the window.
+ *
+ * - the `opened` promise is resolved with `closing` promise and a `closing` event is emitted
+ * - the #getHoldDelay method is called and the returned value is used to time a pause in execution before
+ * the window's {@link OO.ui.Window#getHoldProcess getHoldProces} method is called on the
+ * window and its result executed
+ * - a `hold` progress notification is emitted from the `closing` promise
+ * - the #getTeardownDelay() method is called and the returned value is used to time a pause in execution before
+ * the window's {@link OO.ui.Window#getTeardownProcess getTeardownProcess} method is called on the
+ * window and its result executed
+ * - a `teardown` progress notification is emitted from the `closing` promise
+ * - the `closing` promise is resolved. The window is now closed
+ *
+ * See the [OOjs UI documentation on MediaWiki][1] for more information.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Window_managers
*
* @class
* @extends OO.ui.Element
* @mixins OO.EventEmitter
*
- * Managed windows are mutually exclusive. If a window is opened while there is a current window
- * already opening or opened, the current window will be closed without data. Empty closing data
- * should always result in the window being closed without causing constructive or destructive
- * action.
- *
- * As a window is opened and closed, it passes through several stages and the manager emits several
- * corresponding events.
- *
- * - {@link #openWindow} or {@link OO.ui.Window#open} methods are used to start opening
- * - {@link #event-opening} is emitted with `opening` promise
- * - {@link #getSetupDelay} is called the returned value is used to time a pause in execution
- * - {@link OO.ui.Window#getSetupProcess} method is called on the window and its result executed
- * - `setup` progress notification is emitted from opening promise
- * - {@link #getReadyDelay} is called the returned value is used to time a pause in execution
- * - {@link OO.ui.Window#getReadyProcess} method is called on the window and its result executed
- * - `ready` progress notification is emitted from opening promise
- * - `opening` promise is resolved with `opened` promise
- * - Window is now open
- *
- * - {@link #closeWindow} or {@link OO.ui.Window#close} methods are used to start closing
- * - `opened` promise is resolved with `closing` promise
- * - {@link #event-closing} is emitted with `closing` promise
- * - {@link #getHoldDelay} is called the returned value is used to time a pause in execution
- * - {@link OO.ui.Window#getHoldProcess} method is called on the window and its result executed
- * - `hold` progress notification is emitted from opening promise
- * - {@link #getTeardownDelay} is called the returned value is used to time a pause in execution
- * - {@link OO.ui.Window#getTeardownProcess} method is called on the window and its result executed
- * - `teardown` progress notification is emitted from opening promise
- * - Closing promise is resolved
- * - Window is now closed
- *
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {boolean} [isolate] Configure managed windows to isolate their content using inline frames
* @cfg {OO.Factory} [factory] Window factory to use for automatic instantiation
+ * Note that window classes that are instantiated with a factory must have
+ * a {@link OO.ui.Dialog#static-name static name} property that specifies a symbolic name.
* @cfg {boolean} [modal=true] Prevent interaction outside the dialog
*/
OO.ui.WindowManager = function OoUiWindowManager( config ) {
@@ -2453,22 +2797,18 @@ OO.ui.WindowManager = function OoUiWindowManager( config ) {
// Properties
this.factory = config.factory;
this.modal = config.modal === undefined || !!config.modal;
- this.isolate = !!config.isolate;
this.windows = {};
this.opening = null;
this.opened = null;
this.closing = null;
this.preparingToOpen = null;
this.preparingToClose = null;
- this.size = null;
this.currentWindow = null;
+ this.globalEvents = false;
this.$ariaHidden = null;
- this.requestedSize = null;
this.onWindowResizeTimeout = null;
- this.onWindowResizeHandler = OO.ui.bind( this.onWindowResize, this );
- this.afterWindowResizeHandler = OO.ui.bind( this.afterWindowResize, this );
- this.onWindowMouseWheelHandler = OO.ui.bind( this.onWindowMouseWheel, this );
- this.onDocumentKeyDownHandler = OO.ui.bind( this.onDocumentKeyDown, this );
+ this.onWindowResizeHandler = this.onWindowResize.bind( this );
+ this.afterWindowResizeHandler = this.afterWindowResize.bind( this );
// Initialization
this.$element
@@ -2484,36 +2824,39 @@ OO.mixinClass( OO.ui.WindowManager, OO.EventEmitter );
/* Events */
/**
- * Window is opening.
- *
- * Fired when the window begins to be opened.
+ * An 'opening' event is emitted when the window begins to be opened.
*
* @event opening
* @param {OO.ui.Window} win Window that's being opened
- * @param {jQuery.Promise} opening Promise resolved when window is opened; when the promise is
- * resolved the first argument will be a promise which will be resolved when the window begins
- * closing, the second argument will be the opening data; progress notifications will be fired on
- * the promise for `setup` and `ready` when those processes are completed respectively.
+ * @param {jQuery.Promise} opening An `opening` promise resolved with a value when the window is opened successfully.
+ * When the `opening` promise is resolved, the first argument of the value is an 'opened' promise, the second argument
+ * is the opening data. The `opening` promise emits `setup` and `ready` notifications when those processes are complete.
* @param {Object} data Window opening data
*/
/**
- * Window is closing.
- *
- * Fired when the window begins to be closed.
+ * A 'closing' event is emitted when the window begins to be closed.
*
* @event closing
* @param {OO.ui.Window} win Window that's being closed
- * @param {jQuery.Promise} opening Promise resolved when window is closed; when the promise
- * is resolved the first argument will be a the closing data; progress notifications will be fired
- * on the promise for `hold` and `teardown` when those processes are completed respectively.
+ * @param {jQuery.Promise} closing A `closing` promise is resolved with a value when the window
+ * is closed successfully. The promise emits `hold` and `teardown` notifications when those
+ * processes are complete. When the `closing` promise is resolved, the first argument of its value
+ * is the closing data.
* @param {Object} data Window closing data
*/
+/**
+ * A 'resize' event is emitted when a window is resized.
+ *
+ * @event resize
+ * @param {OO.ui.Window} win Window that was resized
+ */
+
/* Static Properties */
/**
- * Map of symbolic size names and CSS properties.
+ * Map of the symbolic name of each window size and its CSS properties.
*
* @static
* @inheritable
@@ -2529,6 +2872,9 @@ OO.ui.WindowManager.static.sizes = {
large: {
width: 700
},
+ larger: {
+ width: 900
+ },
full: {
// These can be non-numeric because they are never used in calculations
width: '100%',
@@ -2537,9 +2883,9 @@ OO.ui.WindowManager.static.sizes = {
};
/**
- * Symbolic name of default size.
+ * Symbolic name of the default window size.
*
- * Default size is used if the window's requested size is not recognized.
+ * The default size is used if the window's requested size is not recognized.
*
* @static
* @inheritable
@@ -2552,6 +2898,7 @@ OO.ui.WindowManager.static.defaultSize = 'medium';
/**
* Handle window resize events.
*
+ * @private
* @param {jQuery.Event} e Window resize event
*/
OO.ui.WindowManager.prototype.onWindowResize = function () {
@@ -2562,6 +2909,7 @@ OO.ui.WindowManager.prototype.onWindowResize = function () {
/**
* Handle window resize events.
*
+ * @private
* @param {jQuery.Event} e Window resize event
*/
OO.ui.WindowManager.prototype.afterWindowResize = function () {
@@ -2571,35 +2919,6 @@ OO.ui.WindowManager.prototype.afterWindowResize = function () {
};
/**
- * Handle window mouse wheel events.
- *
- * @param {jQuery.Event} e Mouse wheel event
- */
-OO.ui.WindowManager.prototype.onWindowMouseWheel = function () {
- return false;
-};
-
-/**
- * Handle document key down events.
- *
- * @param {jQuery.Event} e Key down event
- */
-OO.ui.WindowManager.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;
- }
-};
-
-/**
* Check if window is opening.
*
* @return {boolean} Window is opening
@@ -2627,17 +2946,6 @@ OO.ui.WindowManager.prototype.isOpened = function ( win ) {
};
/**
- * Check if window contents should be isolated.
- *
- * Window content isolation is done using inline frames.
- *
- * @return {boolean} Window contents should be isolated
- */
-OO.ui.WindowManager.prototype.shouldIsolate = function () {
- return this.isolate;
-};
-
-/**
* Check if a window is being managed.
*
* @param {OO.ui.Window} win Window to check
@@ -2647,7 +2955,7 @@ OO.ui.WindowManager.prototype.hasWindow = function ( win ) {
var name;
for ( name in this.windows ) {
- if ( this.windows[name] === win ) {
+ if ( this.windows[ name ] === win ) {
return true;
}
}
@@ -2656,7 +2964,7 @@ OO.ui.WindowManager.prototype.hasWindow = function ( win ) {
};
/**
- * Get the number of milliseconds to wait between beginning opening and executing setup process.
+ * Get the number of milliseconds to wait after opening begins before executing the ‘setup’ process.
*
* @param {OO.ui.Window} win Window being opened
* @param {Object} [data] Window opening data
@@ -2667,7 +2975,7 @@ OO.ui.WindowManager.prototype.getSetupDelay = function () {
};
/**
- * Get the number of milliseconds to wait between finishing setup and executing ready process.
+ * Get the number of milliseconds to wait after setup has finished before executing the ‘ready’ process.
*
* @param {OO.ui.Window} win Window being opened
* @param {Object} [data] Window opening data
@@ -2678,7 +2986,7 @@ OO.ui.WindowManager.prototype.getReadyDelay = function () {
};
/**
- * Get the number of milliseconds to wait between beginning closing and executing hold process.
+ * Get the number of milliseconds to wait after closing has begun before executing the 'hold' process.
*
* @param {OO.ui.Window} win Window being closed
* @param {Object} [data] Window closing data
@@ -2689,7 +2997,8 @@ OO.ui.WindowManager.prototype.getHoldDelay = function () {
};
/**
- * Get the number of milliseconds to wait between finishing hold and executing teardown process.
+ * Get the number of milliseconds to wait after the ‘hold’ process has finished before
+ * executing the ‘teardown’ process.
*
* @param {OO.ui.Window} win Window being closed
* @param {Object} [data] Window closing data
@@ -2700,18 +3009,21 @@ OO.ui.WindowManager.prototype.getTeardownDelay = function () {
};
/**
- * Get managed window by symbolic name.
+ * Get a window by its symbolic name.
*
- * If window is not yet instantiated, it will be instantiated and added automatically.
+ * If the window is not yet instantiated and its symbolic name is recognized by a factory, it will be
+ * instantiated and added to the window manager automatically. Please see the [OOjs UI documentation on MediaWiki][3]
+ * for more information about using factories.
+ * [3]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Window_managers
*
- * @param {string} name Symbolic window name
+ * @param {string} name Symbolic name of the window
* @return {jQuery.Promise} Promise resolved with matching window, or rejected with an OO.ui.Error
- * @throws {Error} If the symbolic name is unrecognized by the factory
- * @throws {Error} If the symbolic name unrecognized as a managed window
+ * @throws {Error} An error is thrown if the symbolic name is not recognized by the factory.
+ * @throws {Error} An error is thrown if the named window is not recognized as a managed window.
*/
OO.ui.WindowManager.prototype.getWindow = function ( name ) {
var deferred = $.Deferred(),
- win = this.windows[name];
+ win = this.windows[ name ];
if ( !( win instanceof OO.ui.Window ) ) {
if ( this.factory ) {
@@ -2720,7 +3032,7 @@ OO.ui.WindowManager.prototype.getWindow = function ( name ) {
'Cannot auto-instantiate window: symbolic name is unrecognized by the factory'
) );
} else {
- win = this.factory.create( name, this, { $: this.$ } );
+ win = this.factory.create( name );
this.addWindows( [ win ] );
deferred.resolve( win );
}
@@ -2750,13 +3062,12 @@ OO.ui.WindowManager.prototype.getCurrentWindow = function () {
*
* @param {OO.ui.Window|string} win Window object or symbolic name of window to open
* @param {Object} [data] Window opening data
- * @return {jQuery.Promise} Promise resolved when window is done opening; see {@link #event-opening}
- * for more details about the `opening` promise
+ * @return {jQuery.Promise} An `opening` promise resolved when the window is done opening.
+ * See {@link #event-opening 'opening' event} for more information about `opening` promises.
* @fires opening
*/
OO.ui.WindowManager.prototype.openWindow = function ( win, data ) {
var manager = this,
- preparing = [],
opening = $.Deferred();
// Argument handling
@@ -2779,20 +3090,8 @@ OO.ui.WindowManager.prototype.openWindow = function ( win, data ) {
// Window opening
if ( opening.state() !== 'rejected' ) {
- // Begin loading the window if it's not loading or loaded already - may take noticable time
- // and we want to do this in paralell with any other preparatory actions
- if ( !win.isLoading() && !win.isLoaded() ) {
- // Finish initializing the window (must be done after manager is attached to DOM)
- win.setManager( this );
- preparing.push( win.load() );
- }
-
- if ( this.closing ) {
- // If a window is currently closing, wait for it to complete
- preparing.push( this.closing );
- }
-
- this.preparingToOpen = $.when.apply( $, preparing );
+ // If a window is currently closing, wait for it to complete
+ this.preparingToOpen = $.when( this.closing );
// Ensure handlers get called after preparingToOpen is set
this.preparingToOpen.done( function () {
if ( manager.modal ) {
@@ -2828,20 +3127,19 @@ OO.ui.WindowManager.prototype.openWindow = function ( win, data ) {
*
* @param {OO.ui.Window|string} win Window object or symbolic name of window to close
* @param {Object} [data] Window closing data
- * @return {jQuery.Promise} Promise resolved when window is done closing; see {@link #event-closing}
- * for more details about the `closing` promise
- * @throws {Error} If no window by that name is being managed
+ * @return {jQuery.Promise} A `closing` promise resolved when the window is done closing.
+ * See {@link #event-closing 'closing' event} for more information about closing promises.
+ * @throws {Error} An error is thrown if the window is not managed by the window manager.
* @fires closing
*/
OO.ui.WindowManager.prototype.closeWindow = function ( win, data ) {
var manager = this,
- preparing = [],
closing = $.Deferred(),
- opened = this.opened;
+ opened;
// Argument handling
if ( typeof win === 'string' ) {
- win = this.windows[win];
+ win = this.windows[ win ];
} else if ( !this.hasWindow( win ) ) {
win = null;
}
@@ -2863,17 +3161,14 @@ OO.ui.WindowManager.prototype.closeWindow = function ( win, data ) {
// Window closing
if ( closing.state() !== 'rejected' ) {
- if ( this.opening ) {
- // If the window is currently opening, close it when it's done
- preparing.push( this.opening );
- }
-
- this.preparingToClose = $.when.apply( $, preparing );
+ // If the window is currently opening, close it when it's done
+ this.preparingToClose = $.when( this.opening );
// Ensure handlers get called after preparingToClose is set
this.preparingToClose.done( function () {
manager.closing = closing;
manager.preparingToClose = null;
manager.emit( 'closing', win, closing, data );
+ opened = manager.opened;
manager.opened = null;
opened.resolve( closing.promise(), data );
setTimeout( function () {
@@ -2900,71 +3195,82 @@ OO.ui.WindowManager.prototype.closeWindow = function ( win, data ) {
};
/**
- * Add windows.
+ * Add windows to the window manager.
+ *
+ * Windows can be added by reference, symbolic name, or explicitly defined symbolic names.
+ * See the [OOjs ui documentation on MediaWiki] [2] for examples.
+ * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Window_managers
*
- * @param {Object.<string,OO.ui.Window>|OO.ui.Window[]} windows Windows to add
- * @throws {Error} If one of the windows being added without an explicit symbolic name does not have
- * a statically configured symbolic name
+ * @param {Object.<string,OO.ui.Window>|OO.ui.Window[]} windows An array of window objects specified
+ * by reference, symbolic name, or explicitly defined symbolic names.
+ * @throws {Error} An error is thrown if a window is added by symbolic name, but has neither an
+ * explicit nor a statically configured symbolic name.
*/
OO.ui.WindowManager.prototype.addWindows = function ( windows ) {
var i, len, win, name, list;
- if ( $.isArray( windows ) ) {
+ if ( Array.isArray( windows ) ) {
// Convert to map of windows by looking up symbolic names from static configuration
list = {};
for ( i = 0, len = windows.length; i < len; i++ ) {
- name = windows[i].constructor.static.name;
+ name = windows[ i ].constructor.static.name;
if ( typeof name !== 'string' ) {
throw new Error( 'Cannot add window' );
}
- list[name] = windows[i];
+ list[ name ] = windows[ i ];
}
- } else if ( $.isPlainObject( windows ) ) {
+ } else if ( OO.isPlainObject( windows ) ) {
list = windows;
}
// Add windows
for ( name in list ) {
- win = list[name];
- this.windows[name] = win;
+ win = list[ name ];
+ this.windows[ name ] = win.toggle( false );
this.$element.append( win.$element );
+ win.setManager( this );
}
};
/**
- * Remove windows.
+ * Remove the specified windows from the windows manager.
*
- * Windows will be closed before they are removed.
+ * Windows will be closed before they are removed. If you wish to remove all windows, you may wish to use
+ * the #clearWindows method instead. If you no longer need the window manager and want to ensure that it no
+ * longer listens to events, use the #destroy method.
*
- * @param {string} name Symbolic name of window to remove
+ * @param {string[]} names Symbolic names of windows to remove
* @return {jQuery.Promise} Promise resolved when window is closed and removed
- * @throws {Error} If windows being removed are not being managed
+ * @throws {Error} An error is thrown if the named windows are not managed by the window manager.
*/
OO.ui.WindowManager.prototype.removeWindows = function ( names ) {
- var i, len, win, name,
+ var i, len, win, name, cleanupWindow,
manager = this,
promises = [],
cleanup = function ( name, win ) {
- delete manager.windows[name];
+ delete manager.windows[ name ];
win.$element.detach();
};
for ( i = 0, len = names.length; i < len; i++ ) {
- name = names[i];
- win = this.windows[name];
+ name = names[ i ];
+ win = this.windows[ name ];
if ( !win ) {
throw new Error( 'Cannot remove window' );
}
- promises.push( this.closeWindow( name ).then( OO.ui.bind( cleanup, null, name, win ) ) );
+ cleanupWindow = cleanup.bind( null, name, win );
+ promises.push( this.closeWindow( name ).then( cleanupWindow, cleanupWindow ) );
}
return $.when.apply( $, promises );
};
/**
- * Remove all windows.
+ * Remove all windows from the window manager.
*
- * Windows will be closed before they are removed.
+ * Windows will be closed before they are removed. Note that the window manager, though not in use, will still
+ * listen to events. If the window manager will not be used again, you may wish to use the #destroy method instead.
+ * To remove just a subset of windows, use the #removeWindows method.
*
* @return {jQuery.Promise} Promise resolved when all windows are closed and removed
*/
@@ -2973,7 +3279,7 @@ OO.ui.WindowManager.prototype.clearWindows = function () {
};
/**
- * Set dialog size.
+ * Set dialog size. In general, this method should not be called directly.
*
* Fullscreen mode will be used if the dialog is too wide to fit in the screen.
*
@@ -2985,20 +3291,22 @@ OO.ui.WindowManager.prototype.updateWindowSize = function ( win ) {
return;
}
- var viewport = OO.ui.Element.getDimensions( win.getElementWindow() ),
+ var viewport = OO.ui.Element.static.getDimensions( win.getElementWindow() ),
sizes = this.constructor.static.sizes,
size = win.getSize();
- if ( !sizes[size] ) {
+ if ( !sizes[ size ] ) {
size = this.constructor.static.defaultSize;
}
- if ( size !== 'full' && viewport.rect.right - viewport.rect.left < sizes[size].width ) {
+ if ( size !== 'full' && viewport.rect.right - viewport.rect.left < sizes[ size ].width ) {
size = 'full';
}
this.$element.toggleClass( 'oo-ui-windowManager-fullscreen', size === 'full' );
this.$element.toggleClass( 'oo-ui-windowManager-floating', size !== 'full' );
- win.setDimensions( sizes[size] );
+ win.setDimensions( sizes[ size ] );
+
+ this.emit( 'resize', win );
return this;
};
@@ -3006,40 +3314,51 @@ OO.ui.WindowManager.prototype.updateWindowSize = function ( win ) {
/**
* Bind or unbind global events for scrolling.
*
+ * @private
* @param {boolean} [on] Bind global events
* @chainable
*/
OO.ui.WindowManager.prototype.toggleGlobalEvents = function ( on ) {
on = on === undefined ? !!this.globalEvents : !!on;
+ var scrollWidth, bodyMargin,
+ $body = $( this.getElementDocument().body ),
+ // We could have multiple window managers open so only modify
+ // the body css at the bottom of the stack
+ stackDepth = $body.data( 'windowManagerGlobalEvents' ) || 0 ;
+
if ( on ) {
if ( !this.globalEvents ) {
- this.$( this.getElementDocument() ).on( {
- // Prevent scrolling by keys in top-level window
- keydown: this.onDocumentKeyDownHandler
- } );
- this.$( this.getElementWindow() ).on( {
- // Prevent scrolling by wheel in top-level window
- mousewheel: this.onWindowMouseWheelHandler,
+ $( this.getElementWindow() ).on( {
// Start listening for top-level window dimension changes
'orientationchange resize': this.onWindowResizeHandler
} );
+ if ( stackDepth === 0 ) {
+ scrollWidth = window.innerWidth - document.documentElement.clientWidth;
+ bodyMargin = parseFloat( $body.css( 'margin-right' ) ) || 0;
+ $body.css( {
+ overflow: 'hidden',
+ 'margin-right': bodyMargin + scrollWidth
+ } );
+ }
+ stackDepth++;
this.globalEvents = true;
}
} else if ( this.globalEvents ) {
- // Unbind global events
- this.$( this.getElementDocument() ).off( {
- // Allow scrolling by keys in top-level window
- keydown: this.onDocumentKeyDownHandler
- } );
- this.$( this.getElementWindow() ).off( {
- // Allow scrolling by wheel in top-level window
- mousewheel: this.onWindowMouseWheelHandler,
+ $( this.getElementWindow() ).off( {
// Stop listening for top-level window dimension changes
'orientationchange resize': this.onWindowResizeHandler
} );
+ stackDepth--;
+ if ( stackDepth === 0 ) {
+ $body.css( {
+ overflow: '',
+ 'margin-right': ''
+ } );
+ }
this.globalEvents = false;
}
+ $body.data( 'windowManagerGlobalEvents', stackDepth );
return this;
};
@@ -3047,6 +3366,7 @@ OO.ui.WindowManager.prototype.toggleGlobalEvents = function ( on ) {
/**
* Toggle screen reader visibility of content other than the window manager.
*
+ * @private
* @param {boolean} [isolate] Make only the window manager visible to screen readers
* @chainable
*/
@@ -3062,7 +3382,7 @@ OO.ui.WindowManager.prototype.toggleAriaIsolation = function ( isolate ) {
.attr( 'aria-hidden', '' );
}
} else if ( this.$ariaHidden ) {
- // Restore screen reader visiblity
+ // Restore screen reader visibility
this.$ariaHidden.removeAttr( 'aria-hidden' );
this.$ariaHidden = null;
}
@@ -3071,32 +3391,61 @@ OO.ui.WindowManager.prototype.toggleAriaIsolation = function ( isolate ) {
};
/**
- * Destroy window manager.
+ * Destroy the window manager.
*
- * Windows will not be closed, only removed from the DOM.
+ * Destroying the window manager ensures that it will no longer listen to events. If you would like to
+ * continue using the window manager, but wish to remove all windows from it, use the #clearWindows method
+ * instead.
*/
OO.ui.WindowManager.prototype.destroy = function () {
this.toggleGlobalEvents( false );
this.toggleAriaIsolation( false );
+ this.clearWindows();
this.$element.remove();
};
/**
- * @abstract
+ * Errors contain a required message (either a string or jQuery selection) that is used to describe what went wrong
+ * in a {@link OO.ui.Process process}. The error's #recoverable and #warning configurations are used to customize the
+ * appearance and functionality of the error interface.
+ *
+ * The basic error interface contains a formatted error message as well as two buttons: 'Dismiss' and 'Try again' (i.e., the error
+ * is 'recoverable' by default). If the error is not recoverable, the 'Try again' button will not be rendered and the widget
+ * that initiated the failed process will be disabled.
+ *
+ * If the error is a warning, the error interface will include a 'Dismiss' and a 'Continue' button, which will try the
+ * process again.
+ *
+ * For an example of error interfaces, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Processes_and_errors
+ *
* @class
*
* @constructor
* @param {string|jQuery} message Description of error
* @param {Object} [config] Configuration options
- * @cfg {boolean} [recoverable=true] Error is recoverable
+ * @cfg {boolean} [recoverable=true] Error is recoverable.
+ * By default, errors are recoverable, and users can try the process again.
+ * @cfg {boolean} [warning=false] Error is a warning.
+ * If the error is a warning, the error interface will include a
+ * 'Dismiss' and a 'Continue' button. It is the responsibility of the developer to ensure that the warning
+ * is not triggered a second time if the user chooses to continue.
*/
-OO.ui.Error = function OoUiElement( message, config ) {
+OO.ui.Error = function OoUiError( message, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( message ) && config === undefined ) {
+ config = message;
+ message = config.message;
+ }
+
// Configuration initialization
config = config || {};
// Properties
this.message = message instanceof jQuery ? message : String( message );
this.recoverable = config.recoverable === undefined || !!config.recoverable;
+ this.warning = !!config.warning;
};
/* Setup */
@@ -3106,7 +3455,9 @@ OO.initClass( OO.ui.Error );
/* Methods */
/**
- * Check if error can be recovered from.
+ * Check if the error is recoverable.
+ *
+ * If the error is recoverable, users are able to try the process again.
*
* @return {boolean} Error is recoverable
*/
@@ -3115,6 +3466,17 @@ OO.ui.Error.prototype.isRecoverable = function () {
};
/**
+ * Check if the error is a warning.
+ *
+ * If the error is a warning, the error interface will include a 'Dismiss' and a 'Continue' button.
+ *
+ * @return {boolean} Error is warning
+ */
+OO.ui.Error.prototype.isWarning = function () {
+ return this.warning;
+};
+
+/**
* Get error message as DOM nodes.
*
* @return {jQuery} Error message in DOM nodes
@@ -3126,7 +3488,7 @@ OO.ui.Error.prototype.getMessage = function () {
};
/**
- * Get error message as text.
+ * Get the error message text.
*
* @return {string} Error message
*/
@@ -3135,19 +3497,57 @@ OO.ui.Error.prototype.getMessageText = function () {
};
/**
- * A list of functions, called in sequence.
+ * Wraps an HTML snippet for use with configuration values which default
+ * to strings. This bypasses the default html-escaping done to string
+ * values.
+ *
+ * @class
+ *
+ * @constructor
+ * @param {string} [content] HTML content
+ */
+OO.ui.HtmlSnippet = function OoUiHtmlSnippet( content ) {
+ // Properties
+ this.content = content;
+};
+
+/* Setup */
+
+OO.initClass( OO.ui.HtmlSnippet );
+
+/* Methods */
+
+/**
+ * Render into HTML.
+ *
+ * @return {string} Unchanged HTML snippet.
+ */
+OO.ui.HtmlSnippet.prototype.toString = function () {
+ return this.content;
+};
+
+/**
+ * A Process is a list of steps that are called in sequence. The step can be a number, a jQuery promise,
+ * or a function:
*
- * If a function added to a process returns boolean false the process will stop; if it returns an
- * object with a `promise` method the process will use the promise to either continue to the next
- * step when the promise is resolved or stop when the promise is rejected.
+ * - **number**: the process will wait for the specified number of milliseconds before proceeding.
+ * - **promise**: the process will continue to the next step when the promise is successfully resolved
+ * or stop if the promise is rejected.
+ * - **function**: the process will execute the function. The process will stop if the function returns
+ * either a boolean `false` or a promise that is rejected; if the function returns a number, the process
+ * will wait for that number of milliseconds before proceeding.
+ *
+ * If the process fails, an {@link OO.ui.Error error} is generated. Depending on how the error is
+ * configured, users can dismiss the error and try the process again, or not. If a process is stopped,
+ * its remaining steps will not be performed.
*
* @class
*
* @constructor
- * @param {number|jQuery.Promise|Function} step Time to wait, promise to wait for or function to
- * call, see #createStep for more information
- * @param {Object} [context=null] Context to call the step function in, ignored if step is a number
- * or a promise
+ * @param {number|jQuery.Promise|Function} step Number of miliseconds to wait before proceeding, promise
+ * that must be resolved before proceeding, or a function to execute. See #createStep for more information. see #createStep for more information
+ * @param {Object} [context=null] Execution context of the function. The context is ignored if the step is
+ * a number or promise.
* @return {Object} Step object, with `callback` and `context` properties
*/
OO.ui.Process = function ( step, context ) {
@@ -3169,9 +3569,9 @@ OO.initClass( OO.ui.Process );
/**
* Start the process.
*
- * @return {jQuery.Promise} Promise that is resolved when all steps have completed or rejected when
- * any of the steps return boolean false or a promise which gets rejected; upon stopping the
- * process, the remaining steps will not be taken
+ * @return {jQuery.Promise} Promise that is resolved when all steps have successfully completed.
+ * If any of the steps return a promise that is rejected or a boolean false, this promise is rejected
+ * and any remaining steps are not performed.
*/
OO.ui.Process.prototype.execute = function () {
var i, len, promise;
@@ -3206,7 +3606,7 @@ OO.ui.Process.prototype.execute = function () {
// Use rejected promise for error
return $.Deferred().reject( [ result ] ).promise();
}
- if ( $.isArray( result ) && result.length && result[0] instanceof OO.ui.Error ) {
+ if ( Array.isArray( result ) && result.length && result[ 0 ] instanceof OO.ui.Error ) {
// Use rejected promise for list of errors
return $.Deferred().reject( result ).promise();
}
@@ -3222,9 +3622,9 @@ OO.ui.Process.prototype.execute = function () {
if ( this.steps.length ) {
// Generate a chain reaction of promises
- promise = proceed( this.steps[0] )();
+ promise = proceed( this.steps[ 0 ] )();
for ( i = 1, len = this.steps.length; i < len; i++ ) {
- promise = promise.then( proceed( this.steps[i] ) );
+ promise = promise.then( proceed( this.steps[ i ] ) );
}
} else {
promise = $.Deferred().resolve().promise();
@@ -3239,16 +3639,16 @@ OO.ui.Process.prototype.execute = function () {
* @private
* @param {number|jQuery.Promise|Function} step
*
- * - Number of milliseconds to wait; or
- * - Promise to wait to be resolved; or
+ * - Number of milliseconds to wait before proceeding
+ * - Promise that must be resolved before proceeding
* - Function to execute
- * - If it returns boolean false the process will stop
- * - If it returns an object with a `promise` method the process will use the promise to either
- * continue to the next step when the promise is resolved or stop when the promise is rejected
- * - If it returns a number, the process will wait for that number of milliseconds before
- * proceeding
- * @param {Object} [context=null] Context to call the step function in, ignored if step is a number
- * or a promise
+ * - If the function returns a boolean false the process will stop
+ * - If the function returns a promise, the process will continue to the next
+ * step when the promise is resolved or stop if the promise is rejected
+ * - If the function returns a number, the process will wait for that number of
+ * milliseconds before proceeding
+ * @param {Object} [context=null] Execution context of the function. The context is
+ * ignored if the step is a number or promise.
* @return {Object} Step object, with `callback` and `context` properties
*/
OO.ui.Process.prototype.createStep = function ( step, context ) {
@@ -3311,7 +3711,15 @@ OO.inheritClass( OO.ui.ToolFactory, OO.Factory );
/* Methods */
-/** */
+/**
+ * Get tools from the factory
+ *
+ * @param {Array} include Included tools
+ * @param {Array} exclude Excluded tools
+ * @param {Array} promote Promoted tools
+ * @param {Array} demote Demoted tools
+ * @return {string[]} List of tools
+ */
OO.ui.ToolFactory.prototype.getTools = function ( include, exclude, promote, demote ) {
var i, len, included, promoted, demoted,
auto = [],
@@ -3326,8 +3734,8 @@ OO.ui.ToolFactory.prototype.getTools = function ( include, exclude, promote, dem
// Auto
for ( i = 0, len = included.length; i < len; i++ ) {
- if ( !used[included[i]] ) {
- auto.push( included[i] );
+ if ( !used[ included[ i ] ] ) {
+ auto.push( included[ i ] );
}
}
@@ -3355,22 +3763,22 @@ OO.ui.ToolFactory.prototype.extract = function ( collection, used ) {
if ( collection === '*' ) {
for ( name in this.registry ) {
- tool = this.registry[name];
+ tool = this.registry[ name ];
if (
// Only add tools by group name when auto-add is enabled
tool.static.autoAddToCatchall &&
// Exclude already used tools
- ( !used || !used[name] )
+ ( !used || !used[ name ] )
) {
names.push( name );
if ( used ) {
- used[name] = true;
+ used[ name ] = true;
}
}
}
- } else if ( $.isArray( collection ) ) {
+ } else if ( Array.isArray( collection ) ) {
for ( i = 0, len = collection.length; i < len; i++ ) {
- item = collection[i];
+ item = collection[ i ];
// Allow plain strings as shorthand for named tools
if ( typeof item === 'string' ) {
item = { name: item };
@@ -3378,26 +3786,26 @@ OO.ui.ToolFactory.prototype.extract = function ( collection, used ) {
if ( OO.isPlainObject( item ) ) {
if ( item.group ) {
for ( name in this.registry ) {
- tool = this.registry[name];
+ 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.autoAddToGroup &&
// Exclude already used tools
- ( !used || !used[name] )
+ ( !used || !used[ name ] )
) {
names.push( name );
if ( used ) {
- used[name] = true;
+ used[ name ] = true;
}
}
}
// Include tools with matching name and exclude already used tools
- } else if ( item.name && ( !used || !used[item.name] ) ) {
+ } else if ( item.name && ( !used || !used[ item.name ] ) ) {
names.push( item.name );
if ( used ) {
- used[item.name] = true;
+ used[ item.name ] = true;
}
}
}
@@ -3422,7 +3830,7 @@ OO.ui.ToolGroupFactory = function OoUiToolGroupFactory() {
// Register default toolgroups
for ( i = 0, l = defaultClasses.length; i < l; i++ ) {
- this.register( defaultClasses[i] );
+ this.register( defaultClasses[ i ] );
}
};
@@ -3446,19 +3854,207 @@ OO.ui.ToolGroupFactory.static.getDefaultClasses = function () {
};
/**
- * Element with a button.
+ * Theme logic.
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.Theme = function OoUiTheme( config ) {
+ // Configuration initialization
+ config = config || {};
+};
+
+/* Setup */
+
+OO.initClass( OO.ui.Theme );
+
+/* Methods */
+
+/**
+ * Get a list of classes to be applied to a widget.
+ *
+ * The 'on' and 'off' lists combined MUST contain keys for all classes the theme adds or removes,
+ * otherwise state transitions will not work properly.
+ *
+ * @param {OO.ui.Element} element Element for which to get classes
+ * @return {Object.<string,string[]>} Categorized class names with `on` and `off` lists
+ */
+OO.ui.Theme.prototype.getElementClasses = function ( /* element */ ) {
+ return { on: [], off: [] };
+};
+
+/**
+ * Update CSS classes provided by the theme.
+ *
+ * For elements with theme logic hooks, this should be called any time there's a state change.
+ *
+ * @param {OO.ui.Element} element Element for which to update classes
+ * @return {Object.<string,string[]>} Categorized class names with `on` and `off` lists
+ */
+OO.ui.Theme.prototype.updateElementClasses = function ( element ) {
+ var classes = this.getElementClasses( element );
+
+ element.$element
+ .removeClass( classes.off.join( ' ' ) )
+ .addClass( classes.on.join( ' ' ) );
+};
+
+/**
+ * The TabIndexedElement class is an attribute mixin used to add additional functionality to an
+ * element created by another class. The mixin provides a ‘tabIndex’ property, which specifies the
+ * order in which users will navigate through the focusable elements via the "tab" key.
+ *
+ * @example
+ * // TabIndexedElement is mixed into the ButtonWidget class
+ * // to provide a tabIndex property.
+ * var button1 = new OO.ui.ButtonWidget( {
+ * label: 'fourth',
+ * tabIndex: 4
+ * } );
+ * var button2 = new OO.ui.ButtonWidget( {
+ * label: 'second',
+ * tabIndex: 2
+ * } );
+ * var button3 = new OO.ui.ButtonWidget( {
+ * label: 'third',
+ * tabIndex: 3
+ * } );
+ * var button4 = new OO.ui.ButtonWidget( {
+ * label: 'first',
+ * tabIndex: 1
+ * } );
+ * $( 'body' ).append( button1.$element, button2.$element, button3.$element, button4.$element );
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$tabIndexed] The element that should use the tabindex functionality. By default,
+ * the functionality is applied to the element created by the class ($element). If a different element is specified, the tabindex
+ * functionality will be applied to it instead.
+ * @cfg {number|null} [tabIndex=0] Number that specifies the element’s position in the tab-navigation
+ * order (e.g., 1 for the first focusable element). Use 0 to use the default navigation order; use -1
+ * to remove the element from the tab-navigation flow.
+ */
+OO.ui.TabIndexedElement = function OoUiTabIndexedElement( config ) {
+ // Configuration initialization
+ config = $.extend( { tabIndex: 0 }, config );
+
+ // Properties
+ this.$tabIndexed = null;
+ this.tabIndex = null;
+
+ // Events
+ this.connect( this, { disable: 'onDisable' } );
+
+ // Initialization
+ this.setTabIndex( config.tabIndex );
+ this.setTabIndexedElement( config.$tabIndexed || this.$element );
+};
+
+/* Setup */
+
+OO.initClass( OO.ui.TabIndexedElement );
+
+/* Methods */
+
+/**
+ * Set the element that should use the tabindex functionality.
+ *
+ * This method is used to retarget a tabindex mixin so that its functionality applies
+ * to the specified element. If an element is currently using the functionality, the mixin’s
+ * effect on that element is removed before the new element is set up.
+ *
+ * @param {jQuery} $tabIndexed Element that should use the tabindex functionality
+ * @chainable
+ */
+OO.ui.TabIndexedElement.prototype.setTabIndexedElement = function ( $tabIndexed ) {
+ var tabIndex = this.tabIndex;
+ // Remove attributes from old $tabIndexed
+ this.setTabIndex( null );
+ // Force update of new $tabIndexed
+ this.$tabIndexed = $tabIndexed;
+ this.tabIndex = tabIndex;
+ return this.updateTabIndex();
+};
+
+/**
+ * Set the value of the tabindex.
*
- * Buttons are used for controls which can be clicked. They can be configured to use tab indexing
- * and access keys for accessibility purposes.
+ * @param {number|null} tabIndex Tabindex value, or `null` for no tabindex
+ * @chainable
+ */
+OO.ui.TabIndexedElement.prototype.setTabIndex = function ( tabIndex ) {
+ tabIndex = typeof tabIndex === 'number' ? tabIndex : null;
+
+ if ( this.tabIndex !== tabIndex ) {
+ this.tabIndex = tabIndex;
+ this.updateTabIndex();
+ }
+
+ return this;
+};
+
+/**
+ * Update the `tabindex` attribute, in case of changes to tab index or
+ * disabled state.
*
+ * @private
+ * @chainable
+ */
+OO.ui.TabIndexedElement.prototype.updateTabIndex = function () {
+ if ( this.$tabIndexed ) {
+ if ( this.tabIndex !== null ) {
+ // Do not index over disabled elements
+ this.$tabIndexed.attr( {
+ tabindex: this.isDisabled() ? -1 : this.tabIndex,
+ // ChromeVox and NVDA do not seem to inherit this from parent elements
+ 'aria-disabled': this.isDisabled().toString()
+ } );
+ } else {
+ this.$tabIndexed.removeAttr( 'tabindex aria-disabled' );
+ }
+ }
+ return this;
+};
+
+/**
+ * Handle disable events.
+ *
+ * @private
+ * @param {boolean} disabled Element is disabled
+ */
+OO.ui.TabIndexedElement.prototype.onDisable = function () {
+ this.updateTabIndex();
+};
+
+/**
+ * Get the value of the tabindex.
+ *
+ * @return {number|null} Tabindex value
+ */
+OO.ui.TabIndexedElement.prototype.getTabIndex = function () {
+ return this.tabIndex;
+};
+
+/**
+ * ButtonElement is often mixed into other classes to generate a button, which is a clickable
+ * interface element that can be configured with access keys for accessibility.
+ * See the [OOjs UI documentation on MediaWiki] [1] for examples.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Buttons_and_Switches#Buttons
* @abstract
* @class
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {jQuery} [$button] Button node, assigned to #$button, omit to use a generated `<a>`
- * @cfg {boolean} [framed=true] Render button with a frame
- * @cfg {number} [tabIndex=0] Button's tab index, use null to have no tabIndex
+ * @cfg {jQuery} [$button] The button element created by the class.
+ * If this configuration is omitted, the button element will use a generated `<a>`.
+ * @cfg {boolean} [framed=true] Render the button with a frame
* @cfg {string} [accessKey] Button's access key
*/
OO.ui.ButtonElement = function OoUiButtonElement( config ) {
@@ -3468,18 +4064,20 @@ OO.ui.ButtonElement = function OoUiButtonElement( config ) {
// Properties
this.$button = null;
this.framed = null;
- this.tabIndex = null;
this.accessKey = null;
this.active = false;
- this.onMouseUpHandler = OO.ui.bind( this.onMouseUp, this );
- this.onMouseDownHandler = OO.ui.bind( this.onMouseDown, this );
+ this.onMouseUpHandler = this.onMouseUp.bind( this );
+ this.onMouseDownHandler = this.onMouseDown.bind( this );
+ this.onKeyDownHandler = this.onKeyDown.bind( this );
+ this.onKeyUpHandler = this.onKeyUp.bind( this );
+ this.onClickHandler = this.onClick.bind( this );
+ this.onKeyPressHandler = this.onKeyPress.bind( this );
// Initialization
this.$element.addClass( 'oo-ui-buttonElement' );
this.toggleFramed( config.framed === undefined || config.framed );
- this.setTabIndex( config.tabIndex || 0 );
this.setAccessKey( config.accessKey );
- this.setButtonElement( config.$button || this.$( '<a>' ) );
+ this.setButtonElement( config.$button || $( '<a>' ) );
};
/* Setup */
@@ -3491,18 +4089,33 @@ OO.initClass( OO.ui.ButtonElement );
/**
* Cancel mouse down events.
*
+ * This property is usually set to `true` to prevent the focus from changing when the button is clicked.
+ * Classes such as {@link OO.ui.DraggableElement DraggableElement} and {@link OO.ui.ButtonOptionWidget ButtonOptionWidget}
+ * use a value of `false` so that dragging behavior is possible and mousedown events can be handled by a
+ * parent widget.
+ *
* @static
* @inheritable
* @property {boolean}
*/
OO.ui.ButtonElement.static.cancelButtonMouseDownEvents = true;
+/* Events */
+
+/**
+ * A 'click' event is emitted when the button element is clicked.
+ *
+ * @event click
+ */
+
/* Methods */
/**
* Set the button element.
*
- * If an element is already set, it will be cleaned up before setting up the new element.
+ * This method is used to retarget a button mixin so that its functionality applies to
+ * the specified button element instead of the one created by the class. If a button element
+ * is already set, the method will remove the mixin’s effect on that element.
*
* @param {jQuery} $button Element to use as button
*/
@@ -3510,30 +4123,39 @@ OO.ui.ButtonElement.prototype.setButtonElement = function ( $button ) {
if ( this.$button ) {
this.$button
.removeClass( 'oo-ui-buttonElement-button' )
- .removeAttr( 'role accesskey tabindex' )
- .off( this.onMouseDownHandler );
+ .removeAttr( 'role accesskey' )
+ .off( {
+ mousedown: this.onMouseDownHandler,
+ keydown: this.onKeyDownHandler,
+ click: this.onClickHandler,
+ keypress: this.onKeyPressHandler
+ } );
}
this.$button = $button
.addClass( 'oo-ui-buttonElement-button' )
- .attr( { role: 'button', accesskey: this.accessKey, tabindex: this.tabIndex } )
- .on( 'mousedown', this.onMouseDownHandler );
+ .attr( { role: 'button', accesskey: this.accessKey } )
+ .on( {
+ mousedown: this.onMouseDownHandler,
+ keydown: this.onKeyDownHandler,
+ click: this.onClickHandler,
+ keypress: this.onKeyPressHandler
+ } );
};
/**
* Handles mouse down events.
*
+ * @protected
* @param {jQuery.Event} e Mouse down event
*/
OO.ui.ButtonElement.prototype.onMouseDown = function ( e ) {
if ( this.isDisabled() || e.which !== 1 ) {
- return false;
+ return;
}
- // Remove the tab-index while the button is down to prevent the button from stealing focus
- this.$button.removeAttr( 'tabindex' );
this.$element.addClass( 'oo-ui-buttonElement-pressed' );
// Run the mouseup handler no matter where the mouse is when the button is let go, so we can
- // reliably reapply the tabindex and remove the pressed class
+ // reliably remove the pressed class
this.getElementDocument().addEventListener( 'mouseup', this.onMouseUpHandler, true );
// Prevent change of focus unless specifically configured otherwise
if ( this.constructor.static.cancelButtonMouseDownEvents ) {
@@ -3544,62 +4166,109 @@ OO.ui.ButtonElement.prototype.onMouseDown = function ( e ) {
/**
* Handles mouse up events.
*
+ * @protected
* @param {jQuery.Event} e Mouse up event
*/
OO.ui.ButtonElement.prototype.onMouseUp = function ( e ) {
if ( this.isDisabled() || e.which !== 1 ) {
- return false;
+ return;
}
- // Restore the tab-index after the button is up to restore the button's accesssibility
- this.$button.attr( 'tabindex', this.tabIndex );
this.$element.removeClass( 'oo-ui-buttonElement-pressed' );
// Stop listening for mouseup, since we only needed this once
this.getElementDocument().removeEventListener( 'mouseup', this.onMouseUpHandler, true );
};
/**
- * Toggle frame.
+ * Handles mouse click events.
*
- * @param {boolean} [framed] Make button framed, omit to toggle
- * @chainable
+ * @protected
+ * @param {jQuery.Event} e Mouse click event
+ * @fires click
*/
-OO.ui.ButtonElement.prototype.toggleFramed = function ( framed ) {
- framed = framed === undefined ? !this.framed : !!framed;
- if ( framed !== this.framed ) {
- this.framed = framed;
- this.$element
- .toggleClass( 'oo-ui-buttonElement-frameless', !framed )
- .toggleClass( 'oo-ui-buttonElement-framed', framed );
+OO.ui.ButtonElement.prototype.onClick = function ( e ) {
+ if ( !this.isDisabled() && e.which === 1 ) {
+ if ( this.emit( 'click' ) ) {
+ return false;
+ }
}
+};
- return this;
+/**
+ * Handles key down events.
+ *
+ * @protected
+ * @param {jQuery.Event} e Key down event
+ */
+OO.ui.ButtonElement.prototype.onKeyDown = function ( e ) {
+ if ( this.isDisabled() || ( e.which !== OO.ui.Keys.SPACE && e.which !== OO.ui.Keys.ENTER ) ) {
+ return;
+ }
+ this.$element.addClass( 'oo-ui-buttonElement-pressed' );
+ // Run the keyup handler no matter where the key is when the button is let go, so we can
+ // reliably remove the pressed class
+ this.getElementDocument().addEventListener( 'keyup', this.onKeyUpHandler, true );
};
/**
- * Set tab index.
+ * Handles key up events.
*
- * @param {number|null} tabIndex Button's tab index, use null to remove
- * @chainable
+ * @protected
+ * @param {jQuery.Event} e Key up event
*/
-OO.ui.ButtonElement.prototype.setTabIndex = function ( tabIndex ) {
- tabIndex = typeof tabIndex === 'number' && tabIndex >= 0 ? tabIndex : null;
+OO.ui.ButtonElement.prototype.onKeyUp = function ( e ) {
+ if ( this.isDisabled() || ( e.which !== OO.ui.Keys.SPACE && e.which !== OO.ui.Keys.ENTER ) ) {
+ return;
+ }
+ this.$element.removeClass( 'oo-ui-buttonElement-pressed' );
+ // Stop listening for keyup, since we only needed this once
+ this.getElementDocument().removeEventListener( 'keyup', this.onKeyUpHandler, true );
+};
- if ( this.tabIndex !== tabIndex ) {
- if ( this.$button ) {
- if ( tabIndex !== null ) {
- this.$button.attr( 'tabindex', tabIndex );
- } else {
- this.$button.removeAttr( 'tabindex' );
- }
+/**
+ * Handles key press events.
+ *
+ * @protected
+ * @param {jQuery.Event} e Key press event
+ * @fires click
+ */
+OO.ui.ButtonElement.prototype.onKeyPress = function ( e ) {
+ if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
+ if ( this.emit( 'click' ) ) {
+ return false;
}
- this.tabIndex = tabIndex;
+ }
+};
+
+/**
+ * Check if button has a frame.
+ *
+ * @return {boolean} Button is framed
+ */
+OO.ui.ButtonElement.prototype.isFramed = function () {
+ return this.framed;
+};
+
+/**
+ * Render the button with or without a frame. Omit the `framed` parameter to toggle the button frame on and off.
+ *
+ * @param {boolean} [framed] Make button framed, omit to toggle
+ * @chainable
+ */
+OO.ui.ButtonElement.prototype.toggleFramed = function ( framed ) {
+ framed = framed === undefined ? !this.framed : !!framed;
+ if ( framed !== this.framed ) {
+ this.framed = framed;
+ this.$element
+ .toggleClass( 'oo-ui-buttonElement-frameless', !framed )
+ .toggleClass( 'oo-ui-buttonElement-framed', framed );
+ this.updateThemeClasses();
}
return this;
};
/**
- * Set access key.
+ * Set the button's access key.
*
* @param {string} accessKey Button's access key, use empty string to remove
* @chainable
@@ -3622,7 +4291,11 @@ OO.ui.ButtonElement.prototype.setAccessKey = function ( accessKey ) {
};
/**
- * Set active state.
+ * Set the button to its 'active' state.
+ *
+ * The active state occurs when a {@link OO.ui.ButtonOptionWidget ButtonOptionWidget} or
+ * a {@link OO.ui.ToggleButtonWidget ToggleButtonWidget} is pressed. This method does nothing
+ * for other button types.
*
* @param {boolean} [value] Make button active
* @chainable
@@ -3633,17 +4306,23 @@ OO.ui.ButtonElement.prototype.setActive = function ( value ) {
};
/**
- * Element containing a sequence of child elements.
+ * Any OOjs UI widget that contains other widgets (such as {@link OO.ui.ButtonWidget buttons} or
+ * {@link OO.ui.OptionWidget options}) mixes in GroupElement. Adding, removing, and clearing
+ * items from the group is done through the interface the class provides.
+ * For more information, please see the [OOjs UI documentation on MediaWiki] [1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Groups
*
* @abstract
* @class
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {jQuery} [$group] Container node, assigned to #$group, omit to use a generated `<div>`
+ * @cfg {jQuery} [$group] The container element created by the class. If this configuration
+ * is omitted, the group element will use a generated `<div>`.
*/
OO.ui.GroupElement = function OoUiGroupElement( config ) {
- // Configuration
+ // Configuration initialization
config = config || {};
// Properties
@@ -3652,7 +4331,7 @@ OO.ui.GroupElement = function OoUiGroupElement( config ) {
this.aggregateItemEvents = {};
// Initialization
- this.setGroupElement( config.$group || this.$( '<div>' ) );
+ this.setGroupElement( config.$group || $( '<div>' ) );
};
/* Methods */
@@ -3669,12 +4348,12 @@ OO.ui.GroupElement.prototype.setGroupElement = function ( $group ) {
this.$group = $group;
for ( i = 0, len = this.items.length; i < len; i++ ) {
- this.$group.append( this.items[i].$element );
+ this.$group.append( this.items[ i ].$element );
}
};
/**
- * Check if there are no items.
+ * Check if a group contains no items.
*
* @return {boolean} Group is empty
*/
@@ -3683,60 +4362,113 @@ OO.ui.GroupElement.prototype.isEmpty = function () {
};
/**
- * Get items.
+ * Get all items in the group.
*
- * @return {OO.ui.Element[]} Items
+ * The method returns an array of item references (e.g., [button1, button2, button3]) and is useful
+ * when synchronizing groups of items, or whenever the references are required (e.g., when removing items
+ * from a group).
+ *
+ * @return {OO.ui.Element[]} An array of items.
*/
OO.ui.GroupElement.prototype.getItems = function () {
return this.items.slice( 0 );
};
/**
- * Add an aggregate item event.
+ * Get an item by its data.
*
- * Aggregated events are listened to on each item and then emitted by the group under a new name,
- * and with an additional leading parameter containing the item that emitted the original event.
- * Other arguments that were emitted from the original event are passed through.
+ * Only the first item with matching data will be returned. To return all matching items,
+ * use the #getItemsFromData method.
*
- * @param {Object.<string,string|null>} events Aggregate events emitted by group, keyed by item
- * event, use null value to remove aggregation
- * @throws {Error} If aggregation already exists
+ * @param {Object} data Item data to search for
+ * @return {OO.ui.Element|null} Item with equivalent data, `null` if none exists
+ */
+OO.ui.GroupElement.prototype.getItemFromData = function ( data ) {
+ var i, len, item,
+ hash = OO.getHash( data );
+
+ for ( i = 0, len = this.items.length; i < len; i++ ) {
+ item = this.items[ i ];
+ if ( hash === OO.getHash( item.getData() ) ) {
+ return item;
+ }
+ }
+
+ return null;
+};
+
+/**
+ * Get items by their data.
+ *
+ * All items with matching data will be returned. To return only the first match, use the #getItemFromData method instead.
+ *
+ * @param {Object} data Item data to search for
+ * @return {OO.ui.Element[]} Items with equivalent data
+ */
+OO.ui.GroupElement.prototype.getItemsFromData = function ( data ) {
+ var i, len, item,
+ hash = OO.getHash( data ),
+ items = [];
+
+ for ( i = 0, len = this.items.length; i < len; i++ ) {
+ item = this.items[ i ];
+ if ( hash === OO.getHash( item.getData() ) ) {
+ items.push( item );
+ }
+ }
+
+ return items;
+};
+
+/**
+ * Aggregate the events emitted by the group.
+ *
+ * When events are aggregated, the group will listen to all contained items for the event,
+ * and then emit the event under a new name. The new event will contain an additional leading
+ * parameter containing the item that emitted the original event. Other arguments emitted from
+ * the original event are passed through.
+ *
+ * @param {Object.<string,string|null>} events An object keyed by the name of the event that should be
+ * aggregated (e.g., ‘click’) and the value of the new name to use (e.g., ‘groupClick’).
+ * A `null` value will remove aggregated events.
+
+ * @throws {Error} An error is thrown if aggregation already exists.
*/
OO.ui.GroupElement.prototype.aggregate = function ( events ) {
var i, len, item, add, remove, itemEvent, groupEvent;
for ( itemEvent in events ) {
- groupEvent = events[itemEvent];
+ groupEvent = events[ itemEvent ];
// Remove existing aggregated event
- if ( itemEvent in this.aggregateItemEvents ) {
+ if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
// Don't allow duplicate aggregations
if ( groupEvent ) {
throw new Error( 'Duplicate item event aggregation for ' + itemEvent );
}
// Remove event aggregation from existing items
for ( i = 0, len = this.items.length; i < len; i++ ) {
- item = this.items[i];
+ item = this.items[ i ];
if ( item.connect && item.disconnect ) {
remove = {};
- remove[itemEvent] = [ 'emit', groupEvent, item ];
+ remove[ itemEvent ] = [ 'emit', groupEvent, item ];
item.disconnect( this, remove );
}
}
// Prevent future items from aggregating event
- delete this.aggregateItemEvents[itemEvent];
+ delete this.aggregateItemEvents[ itemEvent ];
}
// Add new aggregate event
if ( groupEvent ) {
// Make future items aggregate event
- this.aggregateItemEvents[itemEvent] = groupEvent;
+ this.aggregateItemEvents[ itemEvent ] = groupEvent;
// Add event aggregation to existing items
for ( i = 0, len = this.items.length; i < len; i++ ) {
- item = this.items[i];
+ item = this.items[ i ];
if ( item.connect && item.disconnect ) {
add = {};
- add[itemEvent] = [ 'emit', groupEvent, item ];
+ add[ itemEvent ] = [ 'emit', groupEvent, item ];
item.connect( this, add );
}
}
@@ -3745,12 +4477,13 @@ OO.ui.GroupElement.prototype.aggregate = function ( events ) {
};
/**
- * Add items.
+ * Add items to the group.
*
- * Adding an existing item (by value) will move it.
+ * Items will be added to the end of the group array unless the optional `index` parameter specifies
+ * a different insertion point. Adding an existing item will move it to the end of the array or the point specified by the `index`.
*
- * @param {OO.ui.Element[]} items Item
- * @param {number} [index] Index to insert items at
+ * @param {OO.ui.Element[]} items An array of items to add to the group
+ * @param {number} [index] Index of the insertion point
* @chainable
*/
OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
@@ -3758,7 +4491,7 @@ OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
itemElements = [];
for ( i = 0, len = items.length; i < len; i++ ) {
- item = items[i];
+ item = items[ i ];
// Check if item exists then remove it first, effectively "moving" it
currentIndex = $.inArray( item, this.items );
@@ -3773,7 +4506,7 @@ OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
if ( item.connect && item.disconnect && !$.isEmptyObject( this.aggregateItemEvents ) ) {
events = {};
for ( event in this.aggregateItemEvents ) {
- events[event] = [ 'emit', this.aggregateItemEvents[event], item ];
+ events[ event ] = [ 'emit', this.aggregateItemEvents[ event ], item ];
}
item.connect( this, events );
}
@@ -3788,7 +4521,7 @@ OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
this.$group.prepend( itemElements );
this.items.unshift.apply( this.items, items );
} else {
- this.items[index].$element.before( itemElements );
+ this.items[ index ].$element.before( itemElements );
this.items.splice.apply( this.items, [ index, 0 ].concat( items ) );
}
@@ -3796,11 +4529,12 @@ OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
};
/**
- * Remove items.
+ * Remove the specified items from a group.
*
- * Items will be detached, not removed, so they can be used later.
+ * Removed items are detached (not removed) from the DOM so that they may be reused.
+ * To remove all items from a group, you may wish to use the #clearItems method instead.
*
- * @param {OO.ui.Element[]} items Items to remove
+ * @param {OO.ui.Element[]} items An array of items to remove
* @chainable
*/
OO.ui.GroupElement.prototype.removeItems = function ( items ) {
@@ -3808,7 +4542,7 @@ OO.ui.GroupElement.prototype.removeItems = function ( items ) {
// Remove specific items
for ( i = 0, len = items.length; i < len; i++ ) {
- item = items[i];
+ item = items[ i ];
index = $.inArray( item, this.items );
if ( index !== -1 ) {
if (
@@ -3816,8 +4550,8 @@ OO.ui.GroupElement.prototype.removeItems = function ( items ) {
!$.isEmptyObject( this.aggregateItemEvents )
) {
remove = {};
- if ( itemEvent in this.aggregateItemEvents ) {
- remove[itemEvent] = [ 'emit', this.aggregateItemEvents[itemEvent], item ];
+ if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
+ remove[ itemEvent ] = [ 'emit', this.aggregateItemEvents[ itemEvent ], item ];
}
item.disconnect( this, remove );
}
@@ -3831,9 +4565,10 @@ OO.ui.GroupElement.prototype.removeItems = function ( items ) {
};
/**
- * Clear all items.
+ * Clear all items from the group.
*
- * Items will be detached, not removed, so they can be used later.
+ * Cleared items are detached from the DOM, not removed, so that they may be reused.
+ * To remove only a subset of items from a group, use the #removeItems method.
*
* @chainable
*/
@@ -3842,14 +4577,14 @@ OO.ui.GroupElement.prototype.clearItems = function () {
// Remove all items
for ( i = 0, len = this.items.length; i < len; i++ ) {
- item = this.items[i];
+ item = this.items[ i ];
if (
item.connect && item.disconnect &&
!$.isEmptyObject( this.aggregateItemEvents )
) {
remove = {};
- if ( itemEvent in this.aggregateItemEvents ) {
- remove[itemEvent] = [ 'emit', this.aggregateItemEvents[itemEvent], item ];
+ if ( Object.prototype.hasOwnProperty.call( this.aggregateItemEvents, itemEvent ) ) {
+ remove[ itemEvent ] = [ 'emit', this.aggregateItemEvents[ itemEvent ], item ];
}
item.disconnect( this, remove );
}
@@ -3862,26 +4597,450 @@ OO.ui.GroupElement.prototype.clearItems = function () {
};
/**
- * Element containing an icon.
+ * DraggableElement is a mixin class used to create elements that can be clicked
+ * and dragged by a mouse to a new position within a group. This class must be used
+ * in conjunction with OO.ui.DraggableGroupElement, which provides a container for
+ * the draggable elements.
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ */
+OO.ui.DraggableElement = function OoUiDraggableElement() {
+ // Properties
+ this.index = null;
+
+ // Initialize and events
+ this.$element
+ .attr( 'draggable', true )
+ .addClass( 'oo-ui-draggableElement' )
+ .on( {
+ dragstart: this.onDragStart.bind( this ),
+ dragover: this.onDragOver.bind( this ),
+ dragend: this.onDragEnd.bind( this ),
+ drop: this.onDrop.bind( this )
+ } );
+};
+
+OO.initClass( OO.ui.DraggableElement );
+
+/* Events */
+
+/**
+ * @event dragstart
+ *
+ * A dragstart event is emitted when the user clicks and begins dragging an item.
+ * @param {OO.ui.DraggableElement} item The item the user has clicked and is dragging with the mouse.
+ */
+
+/**
+ * @event dragend
+ * A dragend event is emitted when the user drags an item and releases the mouse,
+ * thus terminating the drag operation.
+ */
+
+/**
+ * @event drop
+ * A drop event is emitted when the user drags an item and then releases the mouse button
+ * over a valid target.
+ */
+
+/* Static Properties */
+
+/**
+ * @inheritdoc OO.ui.ButtonElement
+ */
+OO.ui.DraggableElement.static.cancelButtonMouseDownEvents = false;
+
+/* Methods */
+
+/**
+ * Respond to dragstart event.
+ *
+ * @private
+ * @param {jQuery.Event} event jQuery event
+ * @fires dragstart
+ */
+OO.ui.DraggableElement.prototype.onDragStart = function ( e ) {
+ var dataTransfer = e.originalEvent.dataTransfer;
+ // Define drop effect
+ dataTransfer.dropEffect = 'none';
+ dataTransfer.effectAllowed = 'move';
+ // We must set up a dataTransfer data property or Firefox seems to
+ // ignore the fact the element is draggable.
+ try {
+ dataTransfer.setData( 'application-x/OOjs-UI-draggable', this.getIndex() );
+ } catch ( err ) {
+ // The above is only for firefox. No need to set a catch clause
+ // if it fails, move on.
+ }
+ // Add dragging class
+ this.$element.addClass( 'oo-ui-draggableElement-dragging' );
+ // Emit event
+ this.emit( 'dragstart', this );
+ return true;
+};
+
+/**
+ * Respond to dragend event.
*
- * Icons are graphics, about the size of normal text. They can be used to aid the user in locating
- * a control or convey information in a more space efficient way. Icons should rarely be used
- * without labels; such as in a toolbar where space is at a premium or within a context where the
- * meaning is very clear to the user.
+ * @private
+ * @fires dragend
+ */
+OO.ui.DraggableElement.prototype.onDragEnd = function () {
+ this.$element.removeClass( 'oo-ui-draggableElement-dragging' );
+ this.emit( 'dragend' );
+};
+
+/**
+ * Handle drop event.
+ *
+ * @private
+ * @param {jQuery.Event} event jQuery event
+ * @fires drop
+ */
+OO.ui.DraggableElement.prototype.onDrop = function ( e ) {
+ e.preventDefault();
+ this.emit( 'drop', e );
+};
+
+/**
+ * In order for drag/drop to work, the dragover event must
+ * return false and stop propogation.
+ *
+ * @private
+ */
+OO.ui.DraggableElement.prototype.onDragOver = function ( e ) {
+ e.preventDefault();
+};
+
+/**
+ * Set item index.
+ * Store it in the DOM so we can access from the widget drag event
+ *
+ * @private
+ * @param {number} Item index
+ */
+OO.ui.DraggableElement.prototype.setIndex = function ( index ) {
+ if ( this.index !== index ) {
+ this.index = index;
+ this.$element.data( 'index', index );
+ }
+};
+
+/**
+ * Get item index
+ *
+ * @private
+ * @return {number} Item index
+ */
+OO.ui.DraggableElement.prototype.getIndex = function () {
+ return this.index;
+};
+
+/**
+ * DraggableGroupElement is a mixin class used to create a group element to
+ * contain draggable elements, which are items that can be clicked and dragged by a mouse.
+ * The class is used with OO.ui.DraggableElement.
*
* @abstract
* @class
+ * @mixins OO.ui.GroupElement
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {jQuery} [$icon] Icon node, assigned to #$icon, omit to use a generated `<span>`
- * @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
- * @cfg {string} [iconTitle] Icon title text or a function that returns text
+ * @cfg {string} [orientation] Item orientation: 'horizontal' or 'vertical'. The orientation
+ * should match the layout of the items. Items displayed in a single row
+ * or in several rows should use horizontal orientation. The vertical orientation should only be
+ * used when the items are displayed in a single column. Defaults to 'vertical'
+ */
+OO.ui.DraggableGroupElement = function OoUiDraggableGroupElement( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.GroupElement.call( this, config );
+
+ // Properties
+ this.orientation = config.orientation || 'vertical';
+ this.dragItem = null;
+ this.itemDragOver = null;
+ this.itemKeys = {};
+ this.sideInsertion = '';
+
+ // Events
+ this.aggregate( {
+ dragstart: 'itemDragStart',
+ dragend: 'itemDragEnd',
+ drop: 'itemDrop'
+ } );
+ this.connect( this, {
+ itemDragStart: 'onItemDragStart',
+ itemDrop: 'onItemDrop',
+ itemDragEnd: 'onItemDragEnd'
+ } );
+ this.$element.on( {
+ dragover: $.proxy( this.onDragOver, this ),
+ dragleave: $.proxy( this.onDragLeave, this )
+ } );
+
+ // Initialize
+ if ( Array.isArray( config.items ) ) {
+ this.addItems( config.items );
+ }
+ this.$placeholder = $( '<div>' )
+ .addClass( 'oo-ui-draggableGroupElement-placeholder' );
+ this.$element
+ .addClass( 'oo-ui-draggableGroupElement' )
+ .append( this.$status )
+ .toggleClass( 'oo-ui-draggableGroupElement-horizontal', this.orientation === 'horizontal' )
+ .prepend( this.$placeholder );
+};
+
+/* Setup */
+OO.mixinClass( OO.ui.DraggableGroupElement, OO.ui.GroupElement );
+
+/* Events */
+
+/**
+ * A 'reorder' event is emitted when the order of items in the group changes.
+ *
+ * @event reorder
+ * @param {OO.ui.DraggableElement} item Reordered item
+ * @param {number} [newIndex] New index for the item
+ */
+
+/* Methods */
+
+/**
+ * Respond to item drag start event
+ *
+ * @private
+ * @param {OO.ui.DraggableElement} item Dragged item
+ */
+OO.ui.DraggableGroupElement.prototype.onItemDragStart = function ( item ) {
+ var i, len;
+
+ // Map the index of each object
+ for ( i = 0, len = this.items.length; i < len; i++ ) {
+ this.items[ i ].setIndex( i );
+ }
+
+ if ( this.orientation === 'horizontal' ) {
+ // Set the height of the indicator
+ this.$placeholder.css( {
+ height: item.$element.outerHeight(),
+ width: 2
+ } );
+ } else {
+ // Set the width of the indicator
+ this.$placeholder.css( {
+ height: 2,
+ width: item.$element.outerWidth()
+ } );
+ }
+ this.setDragItem( item );
+};
+
+/**
+ * Respond to item drag end event
+ *
+ * @private
+ */
+OO.ui.DraggableGroupElement.prototype.onItemDragEnd = function () {
+ this.unsetDragItem();
+ return false;
+};
+
+/**
+ * Handle drop event and switch the order of the items accordingly
+ *
+ * @private
+ * @param {OO.ui.DraggableElement} item Dropped item
+ * @fires reorder
+ */
+OO.ui.DraggableGroupElement.prototype.onItemDrop = function ( item ) {
+ var toIndex = item.getIndex();
+ // Check if the dropped item is from the current group
+ // TODO: Figure out a way to configure a list of legally droppable
+ // elements even if they are not yet in the list
+ if ( this.getDragItem() ) {
+ // If the insertion point is 'after', the insertion index
+ // is shifted to the right (or to the left in RTL, hence 'after')
+ if ( this.sideInsertion === 'after' ) {
+ toIndex++;
+ }
+ // Emit change event
+ this.emit( 'reorder', this.getDragItem(), toIndex );
+ }
+ this.unsetDragItem();
+ // Return false to prevent propogation
+ return false;
+};
+
+/**
+ * Handle dragleave event.
+ *
+ * @private
+ */
+OO.ui.DraggableGroupElement.prototype.onDragLeave = function () {
+ // This means the item was dragged outside the widget
+ this.$placeholder
+ .css( 'left', 0 )
+ .addClass( 'oo-ui-element-hidden' );
+};
+
+/**
+ * Respond to dragover event
+ *
+ * @private
+ * @param {jQuery.Event} event Event details
+ */
+OO.ui.DraggableGroupElement.prototype.onDragOver = function ( e ) {
+ var dragOverObj, $optionWidget, itemOffset, itemMidpoint, itemBoundingRect,
+ itemSize, cssOutput, dragPosition, itemIndex, itemPosition,
+ clientX = e.originalEvent.clientX,
+ clientY = e.originalEvent.clientY;
+
+ // Get the OptionWidget item we are dragging over
+ dragOverObj = this.getElementDocument().elementFromPoint( clientX, clientY );
+ $optionWidget = $( dragOverObj ).closest( '.oo-ui-draggableElement' );
+ if ( $optionWidget[ 0 ] ) {
+ itemOffset = $optionWidget.offset();
+ itemBoundingRect = $optionWidget[ 0 ].getBoundingClientRect();
+ itemPosition = $optionWidget.position();
+ itemIndex = $optionWidget.data( 'index' );
+ }
+
+ if (
+ itemOffset &&
+ this.isDragging() &&
+ itemIndex !== this.getDragItem().getIndex()
+ ) {
+ if ( this.orientation === 'horizontal' ) {
+ // Calculate where the mouse is relative to the item width
+ itemSize = itemBoundingRect.width;
+ itemMidpoint = itemBoundingRect.left + itemSize / 2;
+ dragPosition = clientX;
+ // Which side of the item we hover over will dictate
+ // where the placeholder will appear, on the left or
+ // on the right
+ cssOutput = {
+ left: dragPosition < itemMidpoint ? itemPosition.left : itemPosition.left + itemSize,
+ top: itemPosition.top
+ };
+ } else {
+ // Calculate where the mouse is relative to the item height
+ itemSize = itemBoundingRect.height;
+ itemMidpoint = itemBoundingRect.top + itemSize / 2;
+ dragPosition = clientY;
+ // Which side of the item we hover over will dictate
+ // where the placeholder will appear, on the top or
+ // on the bottom
+ cssOutput = {
+ top: dragPosition < itemMidpoint ? itemPosition.top : itemPosition.top + itemSize,
+ left: itemPosition.left
+ };
+ }
+ // Store whether we are before or after an item to rearrange
+ // For horizontal layout, we need to account for RTL, as this is flipped
+ if ( this.orientation === 'horizontal' && this.$element.css( 'direction' ) === 'rtl' ) {
+ this.sideInsertion = dragPosition < itemMidpoint ? 'after' : 'before';
+ } else {
+ this.sideInsertion = dragPosition < itemMidpoint ? 'before' : 'after';
+ }
+ // Add drop indicator between objects
+ this.$placeholder
+ .css( cssOutput )
+ .removeClass( 'oo-ui-element-hidden' );
+ } else {
+ // This means the item was dragged outside the widget
+ this.$placeholder
+ .css( 'left', 0 )
+ .addClass( 'oo-ui-element-hidden' );
+ }
+ // Prevent default
+ e.preventDefault();
+};
+
+/**
+ * Set a dragged item
+ *
+ * @param {OO.ui.DraggableElement} item Dragged item
+ */
+OO.ui.DraggableGroupElement.prototype.setDragItem = function ( item ) {
+ this.dragItem = item;
+};
+
+/**
+ * Unset the current dragged item
+ */
+OO.ui.DraggableGroupElement.prototype.unsetDragItem = function () {
+ this.dragItem = null;
+ this.itemDragOver = null;
+ this.$placeholder.addClass( 'oo-ui-element-hidden' );
+ this.sideInsertion = '';
+};
+
+/**
+ * Get the item that is currently being dragged.
+ *
+ * @return {OO.ui.DraggableElement|null} The currently dragged item, or `null` if no item is being dragged
+ */
+OO.ui.DraggableGroupElement.prototype.getDragItem = function () {
+ return this.dragItem;
+};
+
+/**
+ * Check if an item in the group is currently being dragged.
+ *
+ * @return {Boolean} Item is being dragged
+ */
+OO.ui.DraggableGroupElement.prototype.isDragging = function () {
+ return this.getDragItem() !== null;
+};
+
+/**
+ * IconElement is often mixed into other classes to generate an icon.
+ * Icons are graphics, about the size of normal text. They are used to aid the user
+ * in locating a control or to convey information in a space-efficient way. See the
+ * [OOjs UI documentation on MediaWiki] [1] for a list of icons
+ * included in the library.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Icons
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$icon] The icon element created by the class. If this configuration is omitted,
+ * the icon element will use a generated `<span>`. To use a different HTML tag, or to specify that
+ * the icon element be set to an existing icon instead of the one generated by this class, set a
+ * value using a jQuery selection. For example:
+ *
+ * // Use a <div> tag instead of a <span>
+ * $icon: $("<div>")
+ * // Use an existing icon element instead of the one generated by the class
+ * $icon: this.$element
+ * // Use an icon element from a child widget
+ * $icon: this.childwidget.$element
+ * @cfg {Object|string} [icon=''] The symbolic name of the icon (e.g., ‘remove’ or ‘menu’), or a map of
+ * symbolic names. A map is used for i18n purposes and contains a `default` icon
+ * name and additional names keyed by language code. The `default` name is used when no icon is keyed
+ * by the user's language.
+ *
+ * Example of an i18n map:
+ *
+ * { default: 'bold-a', en: 'bold-b', de: 'bold-f' }
+ * See the [OOjs UI documentation on MediaWiki] [2] for a list of icons included in the library.
+ * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Icons
+ * @cfg {string|Function} [iconTitle] A text string used as the icon title, or a function that returns title
+ * text. The icon title is displayed when users move the mouse over the icon.
*/
OO.ui.IconElement = function OoUiIconElement( config ) {
- // Config intialization
+ // Configuration initialization
config = config || {};
// Properties
@@ -3892,7 +5051,7 @@ OO.ui.IconElement = function OoUiIconElement( config ) {
// Initialization
this.setIcon( config.icon || this.constructor.static.icon );
this.setIconTitle( config.iconTitle || this.constructor.static.iconTitle );
- this.setIconElement( config.$icon || this.$( '<span>' ) );
+ this.setIconElement( config.$icon || $( '<span>' ) );
};
/* Setup */
@@ -3902,40 +5061,41 @@ OO.initClass( OO.ui.IconElement );
/* Static Properties */
/**
- * Icon.
- *
- * Value should be the unique portion of an icon CSS class name, such as 'up' for 'oo-ui-icon-up'.
+ * The symbolic name of the icon (e.g., ‘remove’ or ‘menu’), or a map of symbolic names. A map is used
+ * for i18n purposes and contains a `default` icon name and additional names keyed by
+ * language code. The `default` name is used when no icon is keyed by the user's language.
*
- * 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 an i18n map:
*
- * Example of i18n icon definition:
* { default: 'bold-a', en: 'bold-b', de: 'bold-f' }
*
+ * Note: the static property will be overridden if the #icon configuration is used.
+ *
* @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
+ * @property {Object|string}
*/
OO.ui.IconElement.static.icon = null;
/**
- * Icon title.
+ * The icon title, displayed when users move the mouse over the icon. The value can be text, a
+ * function that returns title text, or `null` for no title.
+ *
+ * The static property will be overridden if the #iconTitle configuration is used.
*
* @static
* @inheritable
- * @property {string|Function|null} Icon title text, a function that returns text or null for no
- * icon title
+ * @property {string|Function|null}
*/
OO.ui.IconElement.static.iconTitle = null;
/* Methods */
/**
- * Set the icon element.
- *
- * If an element is already set, it will be cleaned up before setting up the new element.
+ * Set the icon element. This method is used to retarget an icon mixin so that its functionality
+ * applies to the specified icon element instead of the one created by the class. If an icon
+ * element is already set, the mixin’s effect on that element is removed. Generated CSS classes
+ * and mixin methods will no longer affect the element.
*
* @param {jQuery} $icon Element to use as icon
*/
@@ -3955,11 +5115,12 @@ OO.ui.IconElement.prototype.setIconElement = function ( $icon ) {
};
/**
- * Set icon.
+ * Set icon by symbolic name (e.g., ‘remove’ or ‘menu’). Use `null` to remove an icon.
+ * The icon parameter can also be set to a map of icon names. See the #icon config setting
+ * for an example.
*
- * @param {Object|string|null} 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, use null to remove icon
+ * @param {Object|string|null} icon A symbolic icon name, a {@link #icon map of icon names} keyed
+ * by language code, or `null` to remove the icon.
* @chainable
*/
OO.ui.IconElement.prototype.setIcon = function ( icon ) {
@@ -3979,15 +5140,16 @@ OO.ui.IconElement.prototype.setIcon = function ( icon ) {
}
this.$element.toggleClass( 'oo-ui-iconElement', !!this.icon );
+ this.updateThemeClasses();
return this;
};
/**
- * Set icon title.
+ * Set the icon title. Use `null` to remove the title.
*
- * @param {string|Function|null} icon Icon title text, a function that returns text or null
- * for no icon title
+ * @param {string|Function|null} iconTitle A text string used as the icon title,
+ * a function that returns title text, or `null` for no title.
* @chainable
*/
OO.ui.IconElement.prototype.setIconTitle = function ( iconTitle ) {
@@ -4010,34 +5172,54 @@ OO.ui.IconElement.prototype.setIconTitle = function ( iconTitle ) {
};
/**
- * Get icon.
+ * Get the symbolic name of the icon.
*
- * @return {string} Icon
+ * @return {string} Icon name
*/
OO.ui.IconElement.prototype.getIcon = function () {
return this.icon;
};
/**
- * Element containing an indicator.
+ * Get the icon title. The title text is displayed when a user moves the mouse over the icon.
*
- * Indicators are graphics, smaller than normal text. They can be used to describe unique status or
- * behavior. Indicators should only be used in exceptional cases; such as a button that opens a menu
- * instead of performing an action directly, or an item in a list which has errors that need to be
- * resolved.
+ * @return {string} Icon title text
+ */
+OO.ui.IconElement.prototype.getIconTitle = function () {
+ return this.iconTitle;
+};
+
+/**
+ * IndicatorElement is often mixed into other classes to generate an indicator.
+ * Indicators are small graphics that are generally used in two ways:
+ *
+ * - To draw attention to the status of an item. For example, an indicator might be
+ * used to show that an item in a list has errors that need to be resolved.
+ * - To clarify the function of a control that acts in an exceptional way (a button
+ * that opens a menu instead of performing an action directly, for example).
+ *
+ * For a list of indicators included in the library, please see the
+ * [OOjs UI documentation on MediaWiki] [1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Indicators
*
* @abstract
* @class
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {jQuery} [$indicator] Indicator node, assigned to #$indicator, omit to use a generated
- * `<span>`
- * @cfg {string} [indicator] Symbolic indicator name
- * @cfg {string} [indicatorTitle] Indicator title text or a function that returns text
+ * @cfg {jQuery} [$indicator] The indicator element created by the class. If this
+ * configuration is omitted, the indicator element will use a generated `<span>`.
+ * @cfg {string} [indicator] Symbolic name of the indicator (e.g., ‘alert’ or ‘down’).
+ * See the [OOjs UI documentation on MediaWiki][2] for a list of indicators included
+ * in the library.
+ * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Indicators
+ * @cfg {string|Function} [indicatorTitle] A text string used as the indicator title,
+ * or a function that returns title text. The indicator title is displayed when users move
+ * the mouse over the indicator.
*/
OO.ui.IndicatorElement = function OoUiIndicatorElement( config ) {
- // Config intialization
+ // Configuration initialization
config = config || {};
// Properties
@@ -4048,7 +5230,7 @@ OO.ui.IndicatorElement = function OoUiIndicatorElement( config ) {
// Initialization
this.setIndicator( config.indicator || this.constructor.static.indicator );
this.setIndicatorTitle( config.indicatorTitle || this.constructor.static.indicatorTitle );
- this.setIndicatorElement( config.$indicator || this.$( '<span>' ) );
+ this.setIndicatorElement( config.$indicator || $( '<span>' ) );
};
/* Setup */
@@ -4058,21 +5240,22 @@ OO.initClass( OO.ui.IndicatorElement );
/* Static Properties */
/**
- * indicator.
+ * Symbolic name of the indicator (e.g., ‘alert’ or ‘down’).
+ * The static property will be overridden if the #indicator configuration is used.
*
* @static
* @inheritable
- * @property {string|null} Symbolic indicator name or null for no indicator
+ * @property {string|null}
*/
OO.ui.IndicatorElement.static.indicator = null;
/**
- * Indicator title.
+ * A text string used as the indicator title, a function that returns title text, or `null`
+ * for no title. The static property will be overridden if the #indicatorTitle configuration is used.
*
* @static
* @inheritable
- * @property {string|Function|null} Indicator title text, a function that returns text or null for no
- * indicator title
+ * @property {string|Function|null}
*/
OO.ui.IndicatorElement.static.indicatorTitle = null;
@@ -4096,14 +5279,14 @@ OO.ui.IndicatorElement.prototype.setIndicatorElement = function ( $indicator ) {
.addClass( 'oo-ui-indicatorElement-indicator' )
.toggleClass( 'oo-ui-indicator-' + this.indicator, !!this.indicator );
if ( this.indicatorTitle !== null ) {
- this.$indicatorTitle.attr( 'title', this.indicatorTitle );
+ this.$indicator.attr( 'title', this.indicatorTitle );
}
};
/**
- * Set indicator.
+ * Set the indicator by its symbolic name: ‘alert’, ‘down’, ‘next’, ‘previous’, ‘required’, ‘up’. Use `null` to remove the indicator.
*
- * @param {string|null} indicator Symbolic name of indicator to use or null for no indicator
+ * @param {string|null} indicator Symbolic name of indicator, or `null` for no indicator
* @chainable
*/
OO.ui.IndicatorElement.prototype.setIndicator = function ( indicator ) {
@@ -4122,15 +5305,18 @@ OO.ui.IndicatorElement.prototype.setIndicator = function ( indicator ) {
}
this.$element.toggleClass( 'oo-ui-indicatorElement', !!this.indicator );
+ this.updateThemeClasses();
return this;
};
/**
- * Set indicator title.
+ * Set the indicator title.
+ *
+ * The title is displayed when a user moves the mouse over the indicator.
*
- * @param {string|Function|null} indicator Indicator title text, a function that returns text or
- * null for no indicator title
+ * @param {string|Function|null} indicator Indicator title text, a function that returns text, or
+ * `null` for no indicator title
* @chainable
*/
OO.ui.IndicatorElement.prototype.setIndicatorTitle = function ( indicatorTitle ) {
@@ -4153,16 +5339,18 @@ OO.ui.IndicatorElement.prototype.setIndicatorTitle = function ( indicatorTitle )
};
/**
- * Get indicator.
+ * Get the symbolic name of the indicator (e.g., ‘alert’ or ‘down’).
*
- * @return {string} title Symbolic name of indicator
+ * @return {string} Symbolic name of indicator
*/
OO.ui.IndicatorElement.prototype.getIndicator = function () {
return this.indicator;
};
/**
- * Get indicator title.
+ * Get the indicator title.
+ *
+ * The title is displayed when a user moves the mouse over the indicator.
*
* @return {string} Indicator title text
*/
@@ -4171,19 +5359,28 @@ OO.ui.IndicatorElement.prototype.getIndicatorTitle = function () {
};
/**
- * Element containing a label.
+ * LabelElement is often mixed into other classes to generate a label, which
+ * helps identify the function of an interface element.
+ * See the [OOjs UI documentation on MediaWiki] [1] for more information.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Labels
*
* @abstract
* @class
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {jQuery} [$label] Label node, assigned to #$label, omit to use a generated `<span>`
- * @cfg {jQuery|string|Function} [label] Label nodes, text or a function that returns nodes or text
- * @cfg {boolean} [autoFitLabel=true] Whether to fit the label or not.
+ * @cfg {jQuery} [$label] The label element created by the class. If this
+ * configuration is omitted, the label element will use a generated `<span>`.
+ * @cfg {jQuery|string|Function|OO.ui.HtmlSnippet} [label] The label text. The label can be specified
+ * as a plaintext string, a jQuery selection of elements, or a function that will produce a string
+ * in the future. See the [OOjs UI documentation on MediaWiki] [2] for examples.
+ * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Labels
+ * @cfg {boolean} [autoFitLabel=true] Fit the label to the width of the parent element.
+ * The label will be truncated to fit if necessary.
*/
OO.ui.LabelElement = function OoUiLabelElement( config ) {
- // Config intialization
+ // Configuration initialization
config = config || {};
// Properties
@@ -4193,22 +5390,30 @@ OO.ui.LabelElement = function OoUiLabelElement( config ) {
// Initialization
this.setLabel( config.label || this.constructor.static.label );
- this.setLabelElement( config.$label || this.$( '<span>' ) );
+ this.setLabelElement( config.$label || $( '<span>' ) );
};
/* Setup */
OO.initClass( OO.ui.LabelElement );
+/* Events */
+
+/**
+ * @event labelChange
+ * @param {string} value
+ */
+
/* Static Properties */
/**
- * Label.
+ * The label text. The label can be specified as a plaintext string, a function that will
+ * produce a string in the future, or `null` for no label. The static value will
+ * be overridden if a label is specified with the #label config option.
*
* @static
* @inheritable
- * @property {string|Function|null} Label text; a function that returns nodes or text; or null for
- * no label
+ * @property {string|Function|null}
*/
OO.ui.LabelElement.static.label = null;
@@ -4234,32 +5439,33 @@ OO.ui.LabelElement.prototype.setLabelElement = function ( $label ) {
* Set the label.
*
* An empty string will result in the label being hidden. A string containing only whitespace will
- * be converted to a single &nbsp;
+ * be converted to a single `&nbsp;`.
*
- * @param {jQuery|string|Function|null} label Label nodes; text; a function that returns nodes or
+ * @param {jQuery|string|OO.ui.HtmlSnippet|Function|null} label Label nodes; text; a function that returns nodes or
* text; or null for no label
* @chainable
*/
OO.ui.LabelElement.prototype.setLabel = function ( label ) {
label = typeof label === 'function' ? OO.ui.resolveMsg( label ) : label;
- label = ( typeof label === 'string' && label.length ) || label instanceof jQuery ? label : null;
+ label = ( ( typeof label === 'string' && label.length ) || label instanceof jQuery || label instanceof OO.ui.HtmlSnippet ) ? label : null;
+
+ this.$element.toggleClass( 'oo-ui-labelElement', !!label );
if ( this.label !== label ) {
if ( this.$label ) {
this.setLabelContent( label );
}
this.label = label;
+ this.emit( 'labelChange' );
}
- this.$element.toggleClass( 'oo-ui-labelElement', !!this.label );
-
return this;
};
/**
* Get the label.
*
- * @return {jQuery|string|Function|null} label Label nodes; text; a function that returns nodes or
+ * @return {jQuery|string|Function|null} Label nodes; text; a function that returns nodes or
* text; or null for no label
*/
OO.ui.LabelElement.prototype.getLabel = function () {
@@ -4296,16 +5502,373 @@ OO.ui.LabelElement.prototype.setLabelContent = function ( label ) {
} else {
this.$label.text( label );
}
+ } else if ( label instanceof OO.ui.HtmlSnippet ) {
+ this.$label.html( label.toString() );
} else if ( label instanceof jQuery ) {
this.$label.empty().append( label );
} else {
this.$label.empty();
}
- this.$label.css( 'display', !label ? 'none' : '' );
};
/**
- * Element containing an OO.ui.PopupWidget object.
+ * LookupElement is a mixin that creates a {@link OO.ui.TextInputMenuSelectWidget menu} of suggested values for
+ * a {@link OO.ui.TextInputWidget text input widget}. Suggested values are based on the characters the user types
+ * into the text input field and, in general, the menu is only displayed when the user types. If a suggested value is chosen
+ * from the lookup menu, that value becomes the value of the input field.
+ *
+ * Note that a new menu of suggested items is displayed when a value is chosen from the lookup menu. If this is
+ * not the desired behavior, disable lookup menus with the #setLookupsDisabled method, then set the value, then
+ * re-enable lookups.
+ *
+ * See the [OOjs UI demos][1] for an example.
+ *
+ * [1]: https://tools.wmflabs.org/oojs-ui/oojs-ui/demos/index.html#widgets-apex-vector-ltr
+ *
+ * @class
+ * @abstract
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$overlay] Overlay for the lookup menu; defaults to relative positioning
+ * @cfg {jQuery} [$container=this.$element] The container element. The lookup menu is rendered beneath the specified element.
+ * @cfg {boolean} [allowSuggestionsWhenEmpty=false] Request and display a lookup menu when the text input is empty.
+ * By default, the lookup menu is not generated and displayed until the user begins to type.
+ */
+OO.ui.LookupElement = function OoUiLookupElement( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Properties
+ this.$overlay = config.$overlay || this.$element;
+ this.lookupMenu = new OO.ui.TextInputMenuSelectWidget( this, {
+ widget: this,
+ input: this,
+ $container: config.$container
+ } );
+
+ this.allowSuggestionsWhenEmpty = config.allowSuggestionsWhenEmpty || false;
+
+ this.lookupCache = {};
+ this.lookupQuery = null;
+ this.lookupRequest = null;
+ this.lookupsDisabled = false;
+ this.lookupInputFocused = false;
+
+ // Events
+ this.$input.on( {
+ focus: this.onLookupInputFocus.bind( this ),
+ blur: this.onLookupInputBlur.bind( this ),
+ mousedown: this.onLookupInputMouseDown.bind( this )
+ } );
+ this.connect( this, { change: 'onLookupInputChange' } );
+ this.lookupMenu.connect( this, {
+ toggle: 'onLookupMenuToggle',
+ choose: 'onLookupMenuItemChoose'
+ } );
+
+ // Initialization
+ this.$element.addClass( 'oo-ui-lookupElement' );
+ this.lookupMenu.$element.addClass( 'oo-ui-lookupElement-menu' );
+ this.$overlay.append( this.lookupMenu.$element );
+};
+
+/* Methods */
+
+/**
+ * Handle input focus event.
+ *
+ * @protected
+ * @param {jQuery.Event} e Input focus event
+ */
+OO.ui.LookupElement.prototype.onLookupInputFocus = function () {
+ this.lookupInputFocused = true;
+ this.populateLookupMenu();
+};
+
+/**
+ * Handle input blur event.
+ *
+ * @protected
+ * @param {jQuery.Event} e Input blur event
+ */
+OO.ui.LookupElement.prototype.onLookupInputBlur = function () {
+ this.closeLookupMenu();
+ this.lookupInputFocused = false;
+};
+
+/**
+ * Handle input mouse down event.
+ *
+ * @protected
+ * @param {jQuery.Event} e Input mouse down event
+ */
+OO.ui.LookupElement.prototype.onLookupInputMouseDown = function () {
+ // Only open the menu if the input was already focused.
+ // This way we allow the user to open the menu again after closing it with Esc
+ // by clicking in the input. Opening (and populating) the menu when initially
+ // clicking into the input is handled by the focus handler.
+ if ( this.lookupInputFocused && !this.lookupMenu.isVisible() ) {
+ this.populateLookupMenu();
+ }
+};
+
+/**
+ * Handle input change event.
+ *
+ * @protected
+ * @param {string} value New input value
+ */
+OO.ui.LookupElement.prototype.onLookupInputChange = function () {
+ if ( this.lookupInputFocused ) {
+ this.populateLookupMenu();
+ }
+};
+
+/**
+ * Handle the lookup menu being shown/hidden.
+ *
+ * @protected
+ * @param {boolean} visible Whether the lookup menu is now visible.
+ */
+OO.ui.LookupElement.prototype.onLookupMenuToggle = function ( visible ) {
+ if ( !visible ) {
+ // When the menu is hidden, abort any active request and clear the menu.
+ // This has to be done here in addition to closeLookupMenu(), because
+ // MenuSelectWidget will close itself when the user presses Esc.
+ this.abortLookupRequest();
+ this.lookupMenu.clearItems();
+ }
+};
+
+/**
+ * Handle menu item 'choose' event, updating the text input value to the value of the clicked item.
+ *
+ * @protected
+ * @param {OO.ui.MenuOptionWidget} item Selected item
+ */
+OO.ui.LookupElement.prototype.onLookupMenuItemChoose = function ( item ) {
+ this.setValue( item.getData() );
+};
+
+/**
+ * Get lookup menu.
+ *
+ * @private
+ * @return {OO.ui.TextInputMenuSelectWidget}
+ */
+OO.ui.LookupElement.prototype.getLookupMenu = function () {
+ return this.lookupMenu;
+};
+
+/**
+ * Disable or re-enable lookups.
+ *
+ * When lookups are disabled, calls to #populateLookupMenu will be ignored.
+ *
+ * @param {boolean} disabled Disable lookups
+ */
+OO.ui.LookupElement.prototype.setLookupsDisabled = function ( disabled ) {
+ this.lookupsDisabled = !!disabled;
+};
+
+/**
+ * Open the menu. If there are no entries in the menu, this does nothing.
+ *
+ * @private
+ * @chainable
+ */
+OO.ui.LookupElement.prototype.openLookupMenu = function () {
+ if ( !this.lookupMenu.isEmpty() ) {
+ this.lookupMenu.toggle( true );
+ }
+ return this;
+};
+
+/**
+ * Close the menu, empty it, and abort any pending request.
+ *
+ * @private
+ * @chainable
+ */
+OO.ui.LookupElement.prototype.closeLookupMenu = function () {
+ this.lookupMenu.toggle( false );
+ this.abortLookupRequest();
+ this.lookupMenu.clearItems();
+ return this;
+};
+
+/**
+ * Request menu items based on the input's current value, and when they arrive,
+ * populate the menu with these items and show the menu.
+ *
+ * If lookups have been disabled with #setLookupsDisabled, this function does nothing.
+ *
+ * @private
+ * @chainable
+ */
+OO.ui.LookupElement.prototype.populateLookupMenu = function () {
+ var widget = this,
+ value = this.getValue();
+
+ if ( this.lookupsDisabled ) {
+ return;
+ }
+
+ // If the input is empty, clear the menu, unless suggestions when empty are allowed.
+ if ( !this.allowSuggestionsWhenEmpty && value === '' ) {
+ this.closeLookupMenu();
+ // Skip population if there is already a request pending for the current value
+ } else if ( value !== this.lookupQuery ) {
+ this.getLookupMenuItems()
+ .done( function ( items ) {
+ widget.lookupMenu.clearItems();
+ if ( items.length ) {
+ widget.lookupMenu
+ .addItems( items )
+ .toggle( true );
+ widget.initializeLookupMenuSelection();
+ } else {
+ widget.lookupMenu.toggle( false );
+ }
+ } )
+ .fail( function () {
+ widget.lookupMenu.clearItems();
+ } );
+ }
+
+ return this;
+};
+
+/**
+ * Highlight the first selectable item in the menu.
+ *
+ * @private
+ * @chainable
+ */
+OO.ui.LookupElement.prototype.initializeLookupMenuSelection = function () {
+ if ( !this.lookupMenu.getSelectedItem() ) {
+ this.lookupMenu.highlightItem( this.lookupMenu.getFirstSelectableItem() );
+ }
+};
+
+/**
+ * Get lookup menu items for the current query.
+ *
+ * @private
+ * @return {jQuery.Promise} Promise object which will be passed menu items as the first argument of
+ * the done event. If the request was aborted to make way for a subsequent request, this promise
+ * will not be rejected: it will remain pending forever.
+ */
+OO.ui.LookupElement.prototype.getLookupMenuItems = function () {
+ var widget = this,
+ value = this.getValue(),
+ deferred = $.Deferred(),
+ ourRequest;
+
+ this.abortLookupRequest();
+ if ( Object.prototype.hasOwnProperty.call( this.lookupCache, value ) ) {
+ deferred.resolve( this.getLookupMenuOptionsFromData( this.lookupCache[ value ] ) );
+ } else {
+ this.pushPending();
+ this.lookupQuery = value;
+ ourRequest = this.lookupRequest = this.getLookupRequest();
+ ourRequest
+ .always( function () {
+ // We need to pop pending even if this is an old request, otherwise
+ // the widget will remain pending forever.
+ // TODO: this assumes that an aborted request will fail or succeed soon after
+ // being aborted, or at least eventually. It would be nice if we could popPending()
+ // at abort time, but only if we knew that we hadn't already called popPending()
+ // for that request.
+ widget.popPending();
+ } )
+ .done( function ( response ) {
+ // If this is an old request (and aborting it somehow caused it to still succeed),
+ // ignore its success completely
+ if ( ourRequest === widget.lookupRequest ) {
+ widget.lookupQuery = null;
+ widget.lookupRequest = null;
+ widget.lookupCache[ value ] = widget.getLookupCacheDataFromResponse( response );
+ deferred.resolve( widget.getLookupMenuOptionsFromData( widget.lookupCache[ value ] ) );
+ }
+ } )
+ .fail( function () {
+ // If this is an old request (or a request failing because it's being aborted),
+ // ignore its failure completely
+ if ( ourRequest === widget.lookupRequest ) {
+ widget.lookupQuery = null;
+ widget.lookupRequest = null;
+ deferred.reject();
+ }
+ } );
+ }
+ return deferred.promise();
+};
+
+/**
+ * Abort the currently pending lookup request, if any.
+ *
+ * @private
+ */
+OO.ui.LookupElement.prototype.abortLookupRequest = function () {
+ var oldRequest = this.lookupRequest;
+ if ( oldRequest ) {
+ // First unset this.lookupRequest to the fail handler will notice
+ // that the request is no longer current
+ this.lookupRequest = null;
+ this.lookupQuery = null;
+ oldRequest.abort();
+ }
+};
+
+/**
+ * Get a new request object of the current lookup query value.
+ *
+ * @protected
+ * @abstract
+ * @return {jQuery.Promise} jQuery AJAX object, or promise object with an .abort() method
+ */
+OO.ui.LookupElement.prototype.getLookupRequest = function () {
+ // Stub, implemented in subclass
+ return null;
+};
+
+/**
+ * Pre-process data returned by the request from #getLookupRequest.
+ *
+ * The return value of this function will be cached, and any further queries for the given value
+ * will use the cache rather than doing API requests.
+ *
+ * @protected
+ * @abstract
+ * @param {Mixed} response Response from server
+ * @return {Mixed} Cached result data
+ */
+OO.ui.LookupElement.prototype.getLookupCacheDataFromResponse = function () {
+ // Stub, implemented in subclass
+ return [];
+};
+
+/**
+ * Get a list of menu option widgets from the (possibly cached) data returned by
+ * #getLookupCacheDataFromResponse.
+ *
+ * @protected
+ * @abstract
+ * @param {Mixed} data Cached result data, usually an array
+ * @return {OO.ui.MenuOptionWidget[]} Menu items
+ */
+OO.ui.LookupElement.prototype.getLookupMenuOptionsFromData = function () {
+ // Stub, implemented in subclass
+ return [];
+};
+
+/**
+ * PopupElement is mixed into other classes to generate a {@link OO.ui.PopupWidget popup widget}.
+ * A popup is a container for content. It is overlaid and positioned absolutely. By default, each
+ * popup has an anchor, which is an arrow-like protrusion that points toward the popup’s origin.
+ * See {@link OO.ui.PopupWidget PopupWidget} for an example.
*
* @abstract
* @class
@@ -4313,7 +5876,7 @@ OO.ui.LabelElement.prototype.setLabelContent = function ( label ) {
* @constructor
* @param {Object} [config] Configuration options
* @cfg {Object} [popup] Configuration to pass to popup
- * @cfg {boolean} [autoClose=true] Popup auto-closes when it loses focus
+ * @cfg {boolean} [popup.autoClose=true] Popup auto-closes when it loses focus
*/
OO.ui.PopupElement = function OoUiPopupElement( config ) {
// Configuration initialization
@@ -4323,7 +5886,7 @@ OO.ui.PopupElement = function OoUiPopupElement( config ) {
this.popup = new OO.ui.PopupWidget( $.extend(
{ autoClose: true },
config.popup,
- { $: this.$, $autoCloseIgnore: this.$element }
+ { $autoCloseIgnore: this.$element }
) );
};
@@ -4339,21 +5902,55 @@ OO.ui.PopupElement.prototype.getPopup = function () {
};
/**
- * Element with named flags that can be added, removed, listed and checked.
+ * The FlaggedElement class is an attribute mixin, meaning that it is used to add
+ * additional functionality to an element created by another class. The class provides
+ * a ‘flags’ property assigned the name (or an array of names) of styling flags,
+ * which are used to customize the look and feel of a widget to better describe its
+ * importance and functionality.
+ *
+ * The library currently contains the following styling flags for general use:
+ *
+ * - **progressive**: Progressive styling is applied to convey that the widget will move the user forward in a process.
+ * - **destructive**: Destructive styling is applied to convey that the widget will remove something.
+ * - **constructive**: Constructive styling is applied to convey that the widget will create something.
+ *
+ * The flags affect the appearance of the buttons:
+ *
+ * @example
+ * // FlaggedElement is mixed into ButtonWidget to provide styling flags
+ * var button1 = new OO.ui.ButtonWidget( {
+ * label: 'Constructive',
+ * flags: 'constructive'
+ * } );
+ * var button2 = new OO.ui.ButtonWidget( {
+ * label: 'Destructive',
+ * flags: 'destructive'
+ * } );
+ * var button3 = new OO.ui.ButtonWidget( {
+ * label: 'Progressive',
+ * flags: 'progressive'
+ * } );
+ * $( 'body' ).append( button1.$element, button2.$element, button3.$element );
*
- * A flag, when set, adds a CSS class on the `$element` by combining `oo-ui-flaggedElement-` with
- * the flag name. Flags are primarily useful for styling.
+ * {@link OO.ui.ActionWidget ActionWidgets}, which are a special kind of button that execute an action, use these flags: **primary** and **safe**.
+ * Please see the [OOjs UI documentation on MediaWiki] [1] for more information.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Flagged
*
* @abstract
* @class
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {string[]} [flags=[]] Styling flags, e.g. 'primary', 'destructive' or 'constructive'
- * @cfg {jQuery} [$flagged] Flagged node, assigned to #$flagged, omit to use #$element
+ * @cfg {string|string[]} [flags] The name or names of the flags (e.g., 'constructive' or 'primary') to apply.
+ * Please see the [OOjs UI documentation on MediaWiki] [2] for more information about available flags.
+ * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Elements/Flagged
+ * @cfg {jQuery} [$flagged] The flagged element. By default,
+ * the flagged functionality is applied to the element created by the class ($element).
+ * If a different element is specified, the flagged functionality will be applied to it instead.
*/
OO.ui.FlaggedElement = function OoUiFlaggedElement( config ) {
- // Config initialization
+ // Configuration initialization
config = config || {};
// Properties
@@ -4369,8 +5966,12 @@ OO.ui.FlaggedElement = function OoUiFlaggedElement( config ) {
/**
* @event flag
- * @param {Object.<string,boolean>} changes Object keyed by flag name containing boolean
- * added/removed properties
+ * A flag event is emitted when the #clearFlags or #setFlags methods are used. The `changes`
+ * parameter contains the name of each modified flag and indicates whether it was
+ * added or removed.
+ *
+ * @param {Object.<string,boolean>} changes Object keyed by flag name. A Boolean `true` indicates
+ * that the flag was added, `false` that the flag was removed.
*/
/* Methods */
@@ -4378,9 +5979,10 @@ OO.ui.FlaggedElement = function OoUiFlaggedElement( config ) {
/**
* Set the flagged element.
*
- * If an element is already set, it will be cleaned up before setting up the new element.
+ * This method is used to retarget a flagged mixin so that its functionality applies to the specified element.
+ * If an element is already set, the method will remove the mixin’s effect on that element.
*
- * @param {jQuery} $flagged Element to add flags to
+ * @param {jQuery} $flagged Element that should be flagged
*/
OO.ui.FlaggedElement.prototype.setFlaggedElement = function ( $flagged ) {
var classNames = Object.keys( this.flags ).map( function ( flag ) {
@@ -4395,10 +5997,10 @@ OO.ui.FlaggedElement.prototype.setFlaggedElement = function ( $flagged ) {
};
/**
- * Check if a flag is set.
+ * Check if the specified flag is set.
*
* @param {string} flag Name of flag
- * @return {boolean} Has flag
+ * @return {boolean} The flag is set
*/
OO.ui.FlaggedElement.prototype.hasFlag = function ( flag ) {
return flag in this.flags;
@@ -4407,7 +6009,7 @@ OO.ui.FlaggedElement.prototype.hasFlag = function ( flag ) {
/**
* Get the names of all flags set.
*
- * @return {string[]} flags Flag names
+ * @return {string[]} Flag names
*/
OO.ui.FlaggedElement.prototype.getFlags = function () {
return Object.keys( this.flags );
@@ -4427,8 +6029,8 @@ OO.ui.FlaggedElement.prototype.clearFlags = function () {
for ( flag in this.flags ) {
className = classPrefix + flag;
- changes[flag] = false;
- delete this.flags[flag];
+ changes[ flag ] = false;
+ delete this.flags[ flag ];
remove.push( className );
}
@@ -4436,6 +6038,7 @@ OO.ui.FlaggedElement.prototype.clearFlags = function () {
this.$flagged.removeClass( remove.join( ' ' ) );
}
+ this.updateThemeClasses();
this.emit( 'flag', changes );
return this;
@@ -4444,8 +6047,9 @@ OO.ui.FlaggedElement.prototype.clearFlags = function () {
/**
* Add one or more flags.
*
- * @param {string|string[]|Object.<string, boolean>} flags One or more flags to add, or an object
- * keyed by flag name containing boolean set/remove instructions.
+ * @param {string|string[]|Object.<string, boolean>} flags A flag name, an array of flag names,
+ * or an object keyed by flag name with a boolean value that indicates whether the flag should
+ * be added (`true`) or removed (`false`).
* @chainable
* @fires flag
*/
@@ -4459,36 +6063,36 @@ OO.ui.FlaggedElement.prototype.setFlags = function ( flags ) {
if ( typeof flags === 'string' ) {
className = classPrefix + flags;
// Set
- if ( !this.flags[flags] ) {
- this.flags[flags] = true;
+ if ( !this.flags[ flags ] ) {
+ this.flags[ flags ] = true;
add.push( className );
}
- } else if ( $.isArray( flags ) ) {
+ } else if ( Array.isArray( flags ) ) {
for ( i = 0, len = flags.length; i < len; i++ ) {
- flag = flags[i];
+ flag = flags[ i ];
className = classPrefix + flag;
// Set
- if ( !this.flags[flag] ) {
- changes[flag] = true;
- this.flags[flag] = true;
+ if ( !this.flags[ flag ] ) {
+ changes[ flag ] = true;
+ this.flags[ flag ] = true;
add.push( className );
}
}
} else if ( OO.isPlainObject( flags ) ) {
for ( flag in flags ) {
className = classPrefix + flag;
- if ( flags[flag] ) {
+ if ( flags[ flag ] ) {
// Set
- if ( !this.flags[flag] ) {
- changes[flag] = true;
- this.flags[flag] = true;
+ if ( !this.flags[ flag ] ) {
+ changes[ flag ] = true;
+ this.flags[ flag ] = true;
add.push( className );
}
} else {
// Remove
- if ( this.flags[flag] ) {
- changes[flag] = false;
- delete this.flags[flag];
+ if ( this.flags[ flag ] ) {
+ changes[ flag ] = false;
+ delete this.flags[ flag ];
remove.push( className );
}
}
@@ -4501,27 +6105,39 @@ OO.ui.FlaggedElement.prototype.setFlags = function ( flags ) {
.removeClass( remove.join( ' ' ) );
}
+ this.updateThemeClasses();
this.emit( 'flag', changes );
return this;
};
/**
- * Element with a title.
+ * TitledElement is mixed into other classes to provide a `title` attribute.
+ * Titles are rendered by the browser and are made visible when the user moves
+ * the mouse over the element. Titles are not visible on touch devices.
*
- * Titles are rendered by the browser and are made visible when hovering the element. Titles are
- * not visible on touch devices.
+ * @example
+ * // TitledElement provides a 'title' attribute to the
+ * // ButtonWidget class
+ * var button = new OO.ui.ButtonWidget( {
+ * label: 'Button with Title',
+ * title: 'I am a button'
+ * } );
+ * $( 'body' ).append( button.$element );
*
* @abstract
* @class
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {jQuery} [$titled] Titled node, assigned to #$titled, omit to use #$element
- * @cfg {string|Function} [title] Title text or a function that returns text
+ * @cfg {jQuery} [$titled] The element to which the `title` attribute is applied.
+ * If this config is omitted, the title functionality is applied to $element, the
+ * element created by the class.
+ * @cfg {string|Function} [title] The title text or a function that returns text. If
+ * this config is omitted, the value of the {@link #static-title static title} property is used.
*/
OO.ui.TitledElement = function OoUiTitledElement( config ) {
- // Config intialization
+ // Configuration initialization
config = config || {};
// Properties
@@ -4540,11 +6156,12 @@ OO.initClass( OO.ui.TitledElement );
/* Static Properties */
/**
- * Title.
+ * The title text, a function that returns text, or `null` for no title. The value of the static property
+ * is overridden if the #title config option is used.
*
* @static
* @inheritable
- * @property {string|Function} Title text or a function that returns text
+ * @property {string|Function|null}
*/
OO.ui.TitledElement.static.title = null;
@@ -4553,9 +6170,10 @@ OO.ui.TitledElement.static.title = null;
/**
* Set the titled element.
*
- * If an element is already set, it will be cleaned up before setting up the new element.
+ * This method is used to retarget a titledElement mixin so that its functionality applies to the specified element.
+ * If an element is already set, the mixin’s effect on that element is removed before the new element is set up.
*
- * @param {jQuery} $titled Element to set title on
+ * @param {jQuery} $titled Element that should use the 'titled' functionality
*/
OO.ui.TitledElement.prototype.setTitledElement = function ( $titled ) {
if ( this.$titled ) {
@@ -4571,7 +6189,7 @@ OO.ui.TitledElement.prototype.setTitledElement = function ( $titled ) {
/**
* Set title.
*
- * @param {string|Function|null} title Title text, a function that returns text or null for no title
+ * @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 ) {
@@ -4627,8 +6245,8 @@ OO.ui.ClippableElement = function OoUiClippableElement( config ) {
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 );
+ this.onClippableContainerScrollHandler = this.clip.bind( this );
+ this.onClippableWindowResizeHandler = this.clip.bind( this );
// Initialization
this.setClippableElement( config.$clippable || this.$element );
@@ -4646,9 +6264,8 @@ OO.ui.ClippableElement = function OoUiClippableElement( config ) {
OO.ui.ClippableElement.prototype.setClippableElement = function ( $clippable ) {
if ( this.$clippable ) {
this.$clippable.removeClass( 'oo-ui-clippableElement-clippable' );
- this.$clippable.css( { width: '', height: '' } );
- this.$clippable.width(); // Force reflow for https://code.google.com/p/chromium/issues/detail?id=387290
- this.$clippable.css( { overflowX: '', overflowY: '' } );
+ this.$clippable.css( { width: '', height: '', overflowX: '', overflowY: '' } );
+ OO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );
}
this.$clippable = $clippable.addClass( 'oo-ui-clippableElement-clippable' );
@@ -4669,21 +6286,20 @@ OO.ui.ClippableElement.prototype.toggleClipping = function ( clipping ) {
if ( this.clipping !== clipping ) {
this.clipping = clipping;
if ( clipping ) {
- this.$clippableContainer = this.$( this.getClosestScrollableElementContainer() );
- // If the clippable container is the body, we have to listen to scroll events and check
+ this.$clippableContainer = $( this.getClosestScrollableElementContainer() );
+ // If the clippable container is the root, 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.$clippableScroller = this.$clippableContainer.is( 'html, body' ) ?
+ $( OO.ui.Element.static.getWindow( this.$clippableContainer ) ) :
this.$clippableContainer;
this.$clippableScroller.on( 'scroll', this.onClippableContainerScrollHandler );
- this.$clippableWindow = this.$( this.getElementWindow() )
+ this.$clippableWindow = $( this.getElementWindow() )
.on( 'resize', this.onClippableWindowResizeHandler );
// Initial clip after visible
this.clip();
} else {
- this.$clippable.css( { width: '', height: '' } );
- this.$clippable.width(); // Force reflow for https://code.google.com/p/chromium/issues/detail?id=387290
- this.$clippable.css( { overflowX: '', overflowY: '' } );
+ this.$clippable.css( { width: '', height: '', overflowX: '', overflowY: '' } );
+ OO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );
this.$clippableContainer = null;
this.$clippableScroller.off( 'scroll', this.onClippableContainerScrollHandler );
@@ -4764,35 +6380,42 @@ OO.ui.ClippableElement.prototype.clip = function () {
return this;
}
- var buffer = 10,
+ var buffer = 7, // Chosen by fair dice roll
cOffset = this.$clippable.offset(),
- $container = this.$clippableContainer.is( 'body' ) ?
+ $container = this.$clippableContainer.is( 'html, body' ) ?
this.$clippableWindow : this.$clippableContainer,
ccOffset = $container.offset() || { top: 0, left: 0 },
ccHeight = $container.innerHeight() - buffer,
ccWidth = $container.innerWidth() - buffer,
+ cHeight = this.$clippable.outerHeight() + buffer,
+ cWidth = this.$clippable.outerWidth() + buffer,
scrollTop = this.$clippableScroller.scrollTop(),
scrollLeft = this.$clippableScroller.scrollLeft(),
- desiredWidth = ( ccOffset.left + scrollLeft + ccWidth ) - cOffset.left,
- desiredHeight = ( ccOffset.top + scrollTop + ccHeight ) - cOffset.top,
+ desiredWidth = cOffset.left < 0 ?
+ cWidth + cOffset.left :
+ ( ccOffset.left + scrollLeft + ccWidth ) - cOffset.left,
+ desiredHeight = cOffset.top < 0 ?
+ cHeight + cOffset.top :
+ ( 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( { overflowX: 'auto', width: desiredWidth } );
+ this.$clippable.css( { overflowX: 'scroll', width: desiredWidth } );
} else {
- this.$clippable.css( 'width', this.idealWidth || '' );
- this.$clippable.width(); // Force reflow for https://code.google.com/p/chromium/issues/detail?id=387290
- this.$clippable.css( 'overflowX', '' );
+ this.$clippable.css( { width: this.idealWidth || '', overflowX: '' } );
}
if ( clipHeight ) {
- this.$clippable.css( { overflowY: 'auto', height: desiredHeight } );
+ this.$clippable.css( { overflowY: 'scroll', height: desiredHeight } );
} else {
- this.$clippable.css( 'height', this.idealHeight || '' );
- this.$clippable.height(); // Force reflow for https://code.google.com/p/chromium/issues/detail?id=387290
- this.$clippable.css( 'overflowY', '' );
+ this.$clippable.css( { height: this.idealHeight || '', overflowY: '' } );
+ }
+
+ // If we stopped clipping in at least one of the dimensions
+ if ( !clipWidth || !clipHeight ) {
+ OO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );
}
this.clippedHorizontally = clipWidth;
@@ -4808,6 +6431,8 @@ OO.ui.ClippableElement.prototype.clip = function () {
* @class
* @extends OO.ui.Widget
* @mixins OO.ui.IconElement
+ * @mixins OO.ui.FlaggedElement
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
* @param {OO.ui.ToolGroup} toolGroup
@@ -4815,32 +6440,48 @@ OO.ui.ClippableElement.prototype.clip = function () {
* @cfg {string|Function} [title] Title text or a function that returns text
*/
OO.ui.Tool = function OoUiTool( toolGroup, config ) {
- // Config intialization
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( toolGroup ) && config === undefined ) {
+ config = toolGroup;
+ toolGroup = config.toolGroup;
+ }
+
+ // Configuration initialization
config = config || {};
// Parent constructor
OO.ui.Tool.super.call( this, config );
- // Mixin constructors
- OO.ui.IconElement.call( this, config );
-
// Properties
this.toolGroup = toolGroup;
this.toolbar = this.toolGroup.getToolbar();
this.active = false;
- this.$title = this.$( '<span>' );
- this.$link = this.$( '<a>' );
+ this.$title = $( '<span>' );
+ this.$accel = $( '<span>' );
+ this.$link = $( '<a>' );
this.title = null;
+ // Mixin constructors
+ OO.ui.IconElement.call( this, config );
+ OO.ui.FlaggedElement.call( this, config );
+ OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$link } ) );
+
// Events
this.toolbar.connect( this, { updateState: 'onUpdateState' } );
// Initialization
this.$title.addClass( 'oo-ui-tool-title' );
+ this.$accel
+ .addClass( 'oo-ui-tool-accel' )
+ .prop( {
+ // This may need to be changed if the key names are ever localized,
+ // but for now they are essentially written in English
+ dir: 'ltr',
+ lang: 'en'
+ } );
this.$link
.addClass( 'oo-ui-tool-link' )
- .append( this.$icon, this.$title )
- .prop( 'tabIndex', 0 )
+ .append( this.$icon, this.$title, this.$accel )
.attr( 'role', 'button' );
this.$element
.data( 'oo-ui-tool', this )
@@ -4848,6 +6489,7 @@ OO.ui.Tool = function OoUiTool( toolGroup, config ) {
'oo-ui-tool ' + 'oo-ui-tool-name-' +
this.constructor.static.name.replace( /^([^\/]+)\/([^\/]+).*$/, '$1-$2' )
)
+ .toggleClass( 'oo-ui-tool-with-label', this.constructor.static.displayBothIconAndLabel )
.append( this.$link );
this.setTitle( config.title || this.constructor.static.title );
};
@@ -4856,6 +6498,8 @@ OO.ui.Tool = function OoUiTool( toolGroup, config ) {
OO.inheritClass( OO.ui.Tool, OO.ui.Widget );
OO.mixinClass( OO.ui.Tool, OO.ui.IconElement );
+OO.mixinClass( OO.ui.Tool, OO.ui.FlaggedElement );
+OO.mixinClass( OO.ui.Tool, OO.ui.TabIndexedElement );
/* Events */
@@ -4907,6 +6551,16 @@ OO.ui.Tool.static.group = '';
OO.ui.Tool.static.title = '';
/**
+ * Whether this tool should be displayed with both title and label when used in a bar tool group.
+ * Normally only the icon is displayed, or only the label if no icon is given.
+ *
+ * @static
+ * @inheritable
+ * @property {boolean}
+ */
+OO.ui.Tool.static.displayBothIconAndLabel = false;
+
+/**
* Tool can be automatically added to catch-all groups.
*
* @static
@@ -4967,7 +6621,7 @@ OO.ui.Tool.prototype.onSelect = function () {
/**
* Check if the button is active.
*
- * @param {boolean} Button is active
+ * @return {boolean} Button is active
*/
OO.ui.Tool.prototype.isActive = function () {
return this.active;
@@ -5026,13 +6680,8 @@ OO.ui.Tool.prototype.updateTitle = function () {
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 )
- );
+ this.$title.text( this.title );
+ this.$accel.text( accel );
if ( titleTooltips && typeof this.title === 'string' && this.title.length ) {
tooltipParts.push( this.title );
@@ -5058,6 +6707,254 @@ OO.ui.Tool.prototype.destroy = function () {
/**
* Collection of tool groups.
*
+ * The following is a minimal example using several tools and tool groups.
+ *
+ * @example
+ * // Create the toolbar
+ * var toolFactory = new OO.ui.ToolFactory();
+ * var toolGroupFactory = new OO.ui.ToolGroupFactory();
+ * var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );
+ *
+ * // We will be placing status text in this element when tools are used
+ * var $area = $( '<p>' ).text( 'Toolbar example' );
+ *
+ * // Define the tools that we're going to place in our toolbar
+ *
+ * // Create a class inheriting from OO.ui.Tool
+ * function PictureTool() {
+ * PictureTool.super.apply( this, arguments );
+ * }
+ * OO.inheritClass( PictureTool, OO.ui.Tool );
+ * // Each tool must have a 'name' (used as an internal identifier, see later) and at least one
+ * // of 'icon' and 'title' (displayed icon and text).
+ * PictureTool.static.name = 'picture';
+ * PictureTool.static.icon = 'picture';
+ * PictureTool.static.title = 'Insert picture';
+ * // Defines the action that will happen when this tool is selected (clicked).
+ * PictureTool.prototype.onSelect = function () {
+ * $area.text( 'Picture tool clicked!' );
+ * // Never display this tool as "active" (selected).
+ * this.setActive( false );
+ * };
+ * // Make this tool available in our toolFactory and thus our toolbar
+ * toolFactory.register( PictureTool );
+ *
+ * // Register two more tools, nothing interesting here
+ * function SettingsTool() {
+ * SettingsTool.super.apply( this, arguments );
+ * }
+ * OO.inheritClass( SettingsTool, OO.ui.Tool );
+ * SettingsTool.static.name = 'settings';
+ * SettingsTool.static.icon = 'settings';
+ * SettingsTool.static.title = 'Change settings';
+ * SettingsTool.prototype.onSelect = function () {
+ * $area.text( 'Settings tool clicked!' );
+ * this.setActive( false );
+ * };
+ * toolFactory.register( SettingsTool );
+ *
+ * // Register two more tools, nothing interesting here
+ * function StuffTool() {
+ * StuffTool.super.apply( this, arguments );
+ * }
+ * OO.inheritClass( StuffTool, OO.ui.Tool );
+ * StuffTool.static.name = 'stuff';
+ * StuffTool.static.icon = 'ellipsis';
+ * StuffTool.static.title = 'More stuff';
+ * StuffTool.prototype.onSelect = function () {
+ * $area.text( 'More stuff tool clicked!' );
+ * this.setActive( false );
+ * };
+ * toolFactory.register( StuffTool );
+ *
+ * // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a
+ * // little popup window (a PopupWidget).
+ * function HelpTool( toolGroup, config ) {
+ * OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {
+ * padded: true,
+ * label: 'Help',
+ * head: true
+ * } }, config ) );
+ * this.popup.$body.append( '<p>I am helpful!</p>' );
+ * }
+ * OO.inheritClass( HelpTool, OO.ui.PopupTool );
+ * HelpTool.static.name = 'help';
+ * HelpTool.static.icon = 'help';
+ * HelpTool.static.title = 'Help';
+ * toolFactory.register( HelpTool );
+ *
+ * // Finally define which tools and in what order appear in the toolbar. Each tool may only be
+ * // used once (but not all defined tools must be used).
+ * toolbar.setup( [
+ * {
+ * // 'bar' tool groups display tools' icons only, side-by-side.
+ * type: 'bar',
+ * include: [ 'picture', 'help' ]
+ * },
+ * {
+ * // 'list' tool groups display both the titles and icons, in a dropdown list.
+ * type: 'list',
+ * indicator: 'down',
+ * label: 'More',
+ * include: [ 'settings', 'stuff' ]
+ * }
+ * // Note how the tools themselves are toolgroup-agnostic - the same tool can be displayed
+ * // either in a 'list' or a 'bar'. There is a 'menu' tool group too, not showcased here,
+ * // since it's more complicated to use. (See the next example snippet on this page.)
+ * ] );
+ *
+ * // Create some UI around the toolbar and place it in the document
+ * var frame = new OO.ui.PanelLayout( {
+ * expanded: false,
+ * framed: true
+ * } );
+ * var contentFrame = new OO.ui.PanelLayout( {
+ * expanded: false,
+ * padded: true
+ * } );
+ * frame.$element.append(
+ * toolbar.$element,
+ * contentFrame.$element.append( $area )
+ * );
+ * $( 'body' ).append( frame.$element );
+ *
+ * // Here is where the toolbar is actually built. This must be done after inserting it into the
+ * // document.
+ * toolbar.initialize();
+ *
+ * The following example extends the previous one to illustrate 'menu' tool groups and the usage of
+ * 'updateState' event.
+ *
+ * @example
+ * // Create the toolbar
+ * var toolFactory = new OO.ui.ToolFactory();
+ * var toolGroupFactory = new OO.ui.ToolGroupFactory();
+ * var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );
+ *
+ * // We will be placing status text in this element when tools are used
+ * var $area = $( '<p>' ).text( 'Toolbar example' );
+ *
+ * // Define the tools that we're going to place in our toolbar
+ *
+ * // Create a class inheriting from OO.ui.Tool
+ * function PictureTool() {
+ * PictureTool.super.apply( this, arguments );
+ * }
+ * OO.inheritClass( PictureTool, OO.ui.Tool );
+ * // Each tool must have a 'name' (used as an internal identifier, see later) and at least one
+ * // of 'icon' and 'title' (displayed icon and text).
+ * PictureTool.static.name = 'picture';
+ * PictureTool.static.icon = 'picture';
+ * PictureTool.static.title = 'Insert picture';
+ * // Defines the action that will happen when this tool is selected (clicked).
+ * PictureTool.prototype.onSelect = function () {
+ * $area.text( 'Picture tool clicked!' );
+ * // Never display this tool as "active" (selected).
+ * this.setActive( false );
+ * };
+ * // The toolbar can be synchronized with the state of some external stuff, like a text
+ * // editor's editing area, highlighting the tools (e.g. a 'bold' tool would be shown as active
+ * // when the text cursor was inside bolded text). Here we simply disable this feature.
+ * PictureTool.prototype.onUpdateState = function () {
+ * };
+ * // Make this tool available in our toolFactory and thus our toolbar
+ * toolFactory.register( PictureTool );
+ *
+ * // Register two more tools, nothing interesting here
+ * function SettingsTool() {
+ * SettingsTool.super.apply( this, arguments );
+ * this.reallyActive = false;
+ * }
+ * OO.inheritClass( SettingsTool, OO.ui.Tool );
+ * SettingsTool.static.name = 'settings';
+ * SettingsTool.static.icon = 'settings';
+ * SettingsTool.static.title = 'Change settings';
+ * SettingsTool.prototype.onSelect = function () {
+ * $area.text( 'Settings tool clicked!' );
+ * // Toggle the active state on each click
+ * this.reallyActive = !this.reallyActive;
+ * this.setActive( this.reallyActive );
+ * // To update the menu label
+ * this.toolbar.emit( 'updateState' );
+ * };
+ * SettingsTool.prototype.onUpdateState = function () {
+ * };
+ * toolFactory.register( SettingsTool );
+ *
+ * // Register two more tools, nothing interesting here
+ * function StuffTool() {
+ * StuffTool.super.apply( this, arguments );
+ * this.reallyActive = false;
+ * }
+ * OO.inheritClass( StuffTool, OO.ui.Tool );
+ * StuffTool.static.name = 'stuff';
+ * StuffTool.static.icon = 'ellipsis';
+ * StuffTool.static.title = 'More stuff';
+ * StuffTool.prototype.onSelect = function () {
+ * $area.text( 'More stuff tool clicked!' );
+ * // Toggle the active state on each click
+ * this.reallyActive = !this.reallyActive;
+ * this.setActive( this.reallyActive );
+ * // To update the menu label
+ * this.toolbar.emit( 'updateState' );
+ * };
+ * StuffTool.prototype.onUpdateState = function () {
+ * };
+ * toolFactory.register( StuffTool );
+ *
+ * // This is a PopupTool. Rather than having a custom 'onSelect' action, it will display a
+ * // little popup window (a PopupWidget). 'onUpdateState' is also already implemented.
+ * function HelpTool( toolGroup, config ) {
+ * OO.ui.PopupTool.call( this, toolGroup, $.extend( { popup: {
+ * padded: true,
+ * label: 'Help',
+ * head: true
+ * } }, config ) );
+ * this.popup.$body.append( '<p>I am helpful!</p>' );
+ * }
+ * OO.inheritClass( HelpTool, OO.ui.PopupTool );
+ * HelpTool.static.name = 'help';
+ * HelpTool.static.icon = 'help';
+ * HelpTool.static.title = 'Help';
+ * toolFactory.register( HelpTool );
+ *
+ * // Finally define which tools and in what order appear in the toolbar. Each tool may only be
+ * // used once (but not all defined tools must be used).
+ * toolbar.setup( [
+ * {
+ * // 'bar' tool groups display tools' icons only, side-by-side.
+ * type: 'bar',
+ * include: [ 'picture', 'help' ]
+ * },
+ * {
+ * // 'menu' tool groups display both the titles and icons, in a dropdown menu.
+ * // Menu label indicates which items are selected.
+ * type: 'menu',
+ * indicator: 'down',
+ * include: [ 'settings', 'stuff' ]
+ * }
+ * ] );
+ *
+ * // Create some UI around the toolbar and place it in the document
+ * var frame = new OO.ui.PanelLayout( {
+ * expanded: false,
+ * framed: true
+ * } );
+ * var contentFrame = new OO.ui.PanelLayout( {
+ * expanded: false,
+ * padded: true
+ * } );
+ * frame.$element.append(
+ * toolbar.$element,
+ * contentFrame.$element.append( $area )
+ * );
+ * $( 'body' ).append( frame.$element );
+ *
+ * // Here is where the toolbar is actually built. This must be done after inserting it into the
+ * // document.
+ * toolbar.initialize();
+ * toolbar.emit( 'updateState' );
+ *
* @class
* @extends OO.ui.Element
* @mixins OO.EventEmitter
@@ -5071,6 +6968,13 @@ OO.ui.Tool.prototype.destroy = function () {
* @cfg {boolean} [shadow] Add a shadow below the toolbar
*/
OO.ui.Toolbar = function OoUiToolbar( toolFactory, toolGroupFactory, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( toolFactory ) && config === undefined ) {
+ config = toolFactory;
+ toolFactory = config.toolFactory;
+ toolGroupFactory = config.toolGroupFactory;
+ }
+
// Configuration initialization
config = config || {};
@@ -5086,23 +6990,24 @@ OO.ui.Toolbar = function OoUiToolbar( toolFactory, toolGroupFactory, config ) {
this.toolGroupFactory = toolGroupFactory;
this.groups = [];
this.tools = {};
- this.$bar = this.$( '<div>' );
- this.$actions = this.$( '<div>' );
+ this.$bar = $( '<div>' );
+ this.$actions = $( '<div>' );
this.initialized = false;
+ this.onWindowResizeHandler = this.onWindowResize.bind( this );
// Events
this.$element
.add( this.$bar ).add( this.$group ).add( this.$actions )
- .on( 'mousedown touchstart', OO.ui.bind( this.onPointerDown, this ) );
+ .on( 'mousedown keydown', this.onPointerDown.bind( this ) );
// Initialization
this.$group.addClass( 'oo-ui-toolbar-tools' );
- this.$bar.addClass( 'oo-ui-toolbar-bar' ).append( this.$group );
if ( config.actions ) {
- this.$actions.addClass( 'oo-ui-toolbar-actions' );
- this.$bar.append( this.$actions );
+ this.$bar.append( this.$actions.addClass( 'oo-ui-toolbar-actions' ) );
}
- this.$bar.append( '<div style="clear:both"></div>' );
+ this.$bar
+ .addClass( 'oo-ui-toolbar-bar' )
+ .append( this.$group, '<div style="clear:both"></div>' );
if ( config.shadow ) {
this.$bar.append( '<div class="oo-ui-toolbar-shadow"></div>' );
}
@@ -5141,19 +7046,35 @@ OO.ui.Toolbar.prototype.getToolGroupFactory = function () {
* @param {jQuery.Event} e Mouse down event
*/
OO.ui.Toolbar.prototype.onPointerDown = function ( e ) {
- var $closestWidgetToEvent = this.$( e.target ).closest( '.oo-ui-widget' ),
+ var $closestWidgetToEvent = $( e.target ).closest( '.oo-ui-widget' ),
$closestWidgetToToolbar = this.$element.closest( '.oo-ui-widget' );
- if ( !$closestWidgetToEvent.length || $closestWidgetToEvent[0] === $closestWidgetToToolbar[0] ) {
+ if ( !$closestWidgetToEvent.length || $closestWidgetToEvent[ 0 ] === $closestWidgetToToolbar[ 0 ] ) {
return false;
}
};
/**
+ * Handle window resize event.
+ *
+ * @private
+ * @param {jQuery.Event} e Window resize event
+ */
+OO.ui.Toolbar.prototype.onWindowResize = function () {
+ this.$element.toggleClass(
+ 'oo-ui-toolbar-narrow',
+ this.$bar.width() <= this.narrowThreshold
+ );
+};
+
+/**
* 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.
+ * This must be called after it is attached to a visible document and before doing anything else.
*/
OO.ui.Toolbar.prototype.initialize = function () {
this.initialized = true;
+ this.narrowThreshold = this.$group.width() + this.$actions.width();
+ $( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
+ this.onWindowResize();
};
/**
@@ -5181,20 +7102,20 @@ OO.ui.Toolbar.prototype.setup = function ( groups ) {
// Build out new groups
for ( i = 0, len = groups.length; i < len; i++ ) {
- group = groups[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';
+ group.label = OO.ui.msg( 'ooui-toolbar-more' );
}
}
// Check type has been registered
type = this.getToolGroupFactory().lookup( group.type ) ? group.type : defaultType;
items.push(
- this.getToolGroupFactory().create( type, this, $.extend( { $: this.$ }, group ) )
+ this.getToolGroupFactory().create( type, this, group )
);
}
this.addItems( items );
@@ -5209,7 +7130,7 @@ OO.ui.Toolbar.prototype.reset = function () {
this.groups = [];
this.tools = {};
for ( i = 0, len = this.items.length; i < len; i++ ) {
- this.items[i].destroy();
+ this.items[ i ].destroy();
}
this.clearItems();
};
@@ -5220,6 +7141,7 @@ OO.ui.Toolbar.prototype.reset = function () {
* Call this whenever you are done using a toolbar.
*/
OO.ui.Toolbar.prototype.destroy = function () {
+ $( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
this.reset();
this.$element.remove();
};
@@ -5231,7 +7153,7 @@ OO.ui.Toolbar.prototype.destroy = function () {
* @return {boolean} Tool is available
*/
OO.ui.Toolbar.prototype.isToolAvailable = function ( name ) {
- return !this.tools[name];
+ return !this.tools[ name ];
};
/**
@@ -5240,7 +7162,7 @@ OO.ui.Toolbar.prototype.isToolAvailable = function ( name ) {
* @param {OO.ui.Tool} tool Tool to reserve
*/
OO.ui.Toolbar.prototype.reserveTool = function ( tool ) {
- this.tools[tool.getName()] = tool;
+ this.tools[ tool.getName() ] = tool;
};
/**
@@ -5249,7 +7171,7 @@ OO.ui.Toolbar.prototype.reserveTool = function ( tool ) {
* @param {OO.ui.Tool} tool Tool to release
*/
OO.ui.Toolbar.prototype.releaseTool = function ( tool ) {
- delete this.tools[tool.getName()];
+ delete this.tools[ tool.getName() ];
};
/**
@@ -5287,6 +7209,12 @@ OO.ui.Toolbar.prototype.getToolAccelerator = function () {
* @cfg {Array|string} [demote=[]] List of tools to demote to the end
*/
OO.ui.ToolGroup = function OoUiToolGroup( toolbar, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( toolbar ) && config === undefined ) {
+ config = toolbar;
+ toolbar = config.toolbar;
+ }
+
// Configuration initialization
config = config || {};
@@ -5305,14 +7233,18 @@ OO.ui.ToolGroup = function OoUiToolGroup( toolbar, config ) {
this.exclude = config.exclude || [];
this.promote = config.promote || [];
this.demote = config.demote || [];
- this.onCapturedMouseUpHandler = OO.ui.bind( this.onCapturedMouseUp, this );
+ this.onCapturedMouseKeyUpHandler = this.onCapturedMouseKeyUp.bind( this );
// Events
this.$element.on( {
- 'mousedown touchstart': OO.ui.bind( this.onPointerDown, this ),
- 'mouseup touchend': OO.ui.bind( this.onPointerUp, this ),
- mouseover: OO.ui.bind( this.onMouseOver, this ),
- mouseout: OO.ui.bind( this.onMouseOut, this )
+ mousedown: this.onMouseKeyDown.bind( this ),
+ mouseup: this.onMouseKeyUp.bind( this ),
+ keydown: this.onMouseKeyDown.bind( this ),
+ keyup: this.onMouseKeyUp.bind( this ),
+ focus: this.onMouseOverFocus.bind( this ),
+ blur: this.onMouseOutBlur.bind( this ),
+ mouseover: this.onMouseOverFocus.bind( this ),
+ mouseout: this.onMouseOutBlur.bind( this )
} );
this.toolbar.getToolFactory().connect( this, { register: 'onToolFactoryRegister' } );
this.aggregate( { disable: 'itemDisable' } );
@@ -5383,7 +7315,7 @@ OO.ui.ToolGroup.prototype.updateDisabled = function () {
if ( this.constructor.static.autoDisable ) {
for ( i = this.items.length - 1; i >= 0; i-- ) {
- item = this.items[i];
+ item = this.items[ i ];
if ( !item.isDisabled() ) {
allDisabled = false;
break;
@@ -5395,59 +7327,64 @@ OO.ui.ToolGroup.prototype.updateDisabled = function () {
};
/**
- * Handle mouse down events.
+ * Handle mouse down and key down events.
*
- * @param {jQuery.Event} e Mouse down event
+ * @param {jQuery.Event} e Mouse down or key down event
*/
-OO.ui.ToolGroup.prototype.onPointerDown = function ( e ) {
- // e.which is 0 for touch events, 1 for left mouse button
- if ( !this.isDisabled() && e.which <= 1 ) {
+OO.ui.ToolGroup.prototype.onMouseKeyDown = function ( e ) {
+ if (
+ !this.isDisabled() &&
+ ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
+ ) {
this.pressed = this.getTargetTool( e );
if ( this.pressed ) {
this.pressed.setActive( true );
- this.getElementDocument().addEventListener(
- 'mouseup', this.onCapturedMouseUpHandler, true
- );
+ this.getElementDocument().addEventListener( 'mouseup', this.onCapturedMouseKeyUpHandler, true );
+ this.getElementDocument().addEventListener( 'keyup', this.onCapturedMouseKeyUpHandler, true );
}
+ return false;
}
- return false;
};
/**
- * Handle captured mouse up events.
+ * Handle captured mouse up and key up events.
*
- * @param {Event} e Mouse up event
+ * @param {Event} e Mouse up or key up event
*/
-OO.ui.ToolGroup.prototype.onCapturedMouseUp = function ( e ) {
- this.getElementDocument().removeEventListener( 'mouseup', this.onCapturedMouseUpHandler, true );
- // onPointerUp may be called a second time, depending on where the mouse is when the button is
+OO.ui.ToolGroup.prototype.onCapturedMouseKeyUp = function ( e ) {
+ this.getElementDocument().removeEventListener( 'mouseup', this.onCapturedMouseKeyUpHandler, true );
+ this.getElementDocument().removeEventListener( 'keyup', this.onCapturedMouseKeyUpHandler, true );
+ // onMouseKeyUp 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.onPointerUp( e );
+ this.onMouseKeyUp( e );
};
/**
- * Handle mouse up events.
+ * Handle mouse up and key up events.
*
- * @param {jQuery.Event} e Mouse up event
+ * @param {jQuery.Event} e Mouse up or key up event
*/
-OO.ui.ToolGroup.prototype.onPointerUp = function ( e ) {
+OO.ui.ToolGroup.prototype.onMouseKeyUp = function ( e ) {
var tool = this.getTargetTool( e );
- // e.which is 0 for touch events, 1 for left mouse button
- if ( !this.isDisabled() && e.which <= 1 && this.pressed && this.pressed === tool ) {
+ if (
+ !this.isDisabled() && this.pressed && this.pressed === tool &&
+ ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
+ ) {
this.pressed.onSelect();
+ this.pressed = null;
+ return false;
}
this.pressed = null;
- return false;
};
/**
- * Handle mouse over events.
+ * Handle mouse over and focus events.
*
- * @param {jQuery.Event} e Mouse over event
+ * @param {jQuery.Event} e Mouse over or focus event
*/
-OO.ui.ToolGroup.prototype.onMouseOver = function ( e ) {
+OO.ui.ToolGroup.prototype.onMouseOverFocus = function ( e ) {
var tool = this.getTargetTool( e );
if ( this.pressed && this.pressed === tool ) {
@@ -5456,11 +7393,11 @@ OO.ui.ToolGroup.prototype.onMouseOver = function ( e ) {
};
/**
- * Handle mouse out events.
+ * Handle mouse out and blur events.
*
- * @param {jQuery.Event} e Mouse out event
+ * @param {jQuery.Event} e Mouse out or blur event
*/
-OO.ui.ToolGroup.prototype.onMouseOut = function ( e ) {
+OO.ui.ToolGroup.prototype.onMouseOutBlur = function ( e ) {
var tool = this.getTargetTool( e );
if ( this.pressed && this.pressed === tool ) {
@@ -5480,7 +7417,7 @@ OO.ui.ToolGroup.prototype.onMouseOut = function ( e ) {
*/
OO.ui.ToolGroup.prototype.getTargetTool = function ( e ) {
var tool,
- $item = this.$( e.target ).closest( '.oo-ui-tool-link' );
+ $item = $( e.target ).closest( '.oo-ui-tool-link' );
if ( $item.length ) {
tool = $item.parent().data( 'oo-ui-tool' );
@@ -5527,31 +7464,34 @@ OO.ui.ToolGroup.prototype.populate = function () {
// Build a list of needed tools
for ( i = 0, len = list.length; i < len; i++ ) {
- name = list[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] )
+ ( this.toolbar.isToolAvailable( name ) || this.tools[ name ] )
) {
- tool = this.tools[name];
+ // Hack to prevent infinite recursion via ToolGroupTool. We need to reserve the tool before
+ // creating it, but we can't call reserveTool() yet because we haven't created the tool.
+ this.toolbar.tools[ name ] = true;
+ tool = this.tools[ name ];
if ( !tool ) {
// Auto-initialize tools on first use
- this.tools[name] = tool = toolFactory.create( name, this );
+ this.tools[ name ] = tool = toolFactory.create( name, this );
tool.updateTitle();
}
this.toolbar.reserveTool( tool );
add.push( tool );
- names[name] = true;
+ 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 ( !names[ name ] ) {
+ this.tools[ name ].destroy();
+ this.toolbar.releaseTool( this.tools[ name ] );
+ remove.push( this.tools[ name ] );
+ delete this.tools[ name ];
}
}
if ( remove.length ) {
@@ -5578,19 +7518,47 @@ OO.ui.ToolGroup.prototype.destroy = function () {
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.toolbar.releaseTool( this.tools[ name ] );
+ this.tools[ name ].disconnect( this ).destroy();
+ delete this.tools[ name ];
}
this.$element.remove();
};
/**
- * Dialog for showing a message.
+ * MessageDialogs display a confirmation or alert message. By default, the rendered dialog box
+ * consists of a header that contains the dialog title, a body with the message, and a footer that
+ * contains any {@link OO.ui.ActionWidget action widgets}. The MessageDialog class is the only type
+ * of {@link OO.ui.Dialog dialog} that is usually instantiated directly.
+ *
+ * There are two basic types of message dialogs, confirmation and alert:
+ *
+ * - **confirmation**: the dialog title describes what a progressive action will do and the message provides
+ * more details about the consequences.
+ * - **alert**: the dialog title describes which event occurred and the message provides more information
+ * about why the event occurred.
+ *
+ * The MessageDialog class specifies two actions: ‘accept’, the primary
+ * action (e.g., ‘ok’) and ‘reject,’ the safe action (e.g., ‘cancel’). Both will close the window,
+ * passing along the selected action.
+ *
+ * For more information and examples, please see the [OOjs UI documentation on MediaWiki][1].
*
- * User interface:
- * - Registers two actions by default (safe and primary).
- * - Renders action widgets in the footer.
+ * @example
+ * // Example: Creating and opening a message dialog window.
+ * var messageDialog = new OO.ui.MessageDialog();
+ *
+ * // Create and append a window manager.
+ * var windowManager = new OO.ui.WindowManager();
+ * $( 'body' ).append( windowManager.$element );
+ * windowManager.addWindows( [ messageDialog ] );
+ * // Open the window.
+ * windowManager.openWindow( messageDialog, {
+ * title: 'Basic message dialog',
+ * message: 'This is the message'
+ * } );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Message_Dialogs
*
* @class
* @extends OO.ui.Dialog
@@ -5624,21 +7592,23 @@ OO.ui.MessageDialog.static.verbose = false;
/**
* Dialog title.
*
- * A confirmation dialog's title should describe what the progressive action will do. An alert
- * dialog's title should describe what event occured.
+ * The title of a confirmation dialog describes what a progressive action will do. The
+ * title of an alert dialog describes which event occurred.
*
* @static
- * inheritable
+ * @inheritable
* @property {jQuery|string|Function|null}
*/
OO.ui.MessageDialog.static.title = null;
/**
- * A confirmation dialog's message should describe the consequences of the progressive action. An
- * alert dialog's message should describe why the event occured.
+ * The message displayed in the dialog body.
+ *
+ * A confirmation message describes the consequences of a progressive action. An alert
+ * message describes why an event occurred.
*
* @static
- * inheritable
+ * @inheritable
* @property {jQuery|string|Function|null}
*/
OO.ui.MessageDialog.static.message = null;
@@ -5653,14 +7623,44 @@ OO.ui.MessageDialog.static.actions = [
/**
* @inheritdoc
*/
+OO.ui.MessageDialog.prototype.setManager = function ( manager ) {
+ OO.ui.MessageDialog.super.prototype.setManager.call( this, manager );
+
+ // Events
+ this.manager.connect( this, {
+ resize: 'onResize'
+ } );
+
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
OO.ui.MessageDialog.prototype.onActionResize = function ( action ) {
this.fitActions();
- return OO.ui.ProcessDialog.super.prototype.onActionResize.call( this, action );
+ return OO.ui.MessageDialog.super.prototype.onActionResize.call( this, action );
+};
+
+/**
+ * Handle window resized events.
+ *
+ * @private
+ */
+OO.ui.MessageDialog.prototype.onResize = function () {
+ var dialog = this;
+ dialog.fitActions();
+ // Wait for CSS transition to finish and do it again :(
+ setTimeout( function () {
+ dialog.fitActions();
+ }, 300 );
};
/**
* Toggle action layout between vertical and horizontal.
*
+ *
+ * @private
* @param {boolean} [value] Layout actions vertically, omit to toggle
* @chainable
*/
@@ -5722,7 +7722,39 @@ OO.ui.MessageDialog.prototype.getSetupProcess = function ( data ) {
* @inheritdoc
*/
OO.ui.MessageDialog.prototype.getBodyHeight = function () {
- return Math.round( this.text.$element.outerHeight( true ) );
+ var bodyHeight, oldOverflow,
+ $scrollable = this.container.$element;
+
+ oldOverflow = $scrollable[ 0 ].style.overflow;
+ $scrollable[ 0 ].style.overflow = 'hidden';
+
+ OO.ui.Element.static.reconsiderScrollbars( $scrollable[ 0 ] );
+
+ bodyHeight = this.text.$element.outerHeight( true );
+ $scrollable[ 0 ].style.overflow = oldOverflow;
+
+ return bodyHeight;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.MessageDialog.prototype.setDimensions = function ( dim ) {
+ var $scrollable = this.container.$element;
+ OO.ui.MessageDialog.super.prototype.setDimensions.call( this, dim );
+
+ // Twiddle the overflow property, otherwise an unnecessary scrollbar will be produced.
+ // Need to do it after transition completes (250ms), add 50ms just in case.
+ setTimeout( function () {
+ var oldOverflow = $scrollable[ 0 ].style.overflow;
+ $scrollable[ 0 ].style.overflow = 'hidden';
+
+ OO.ui.Element.static.reconsiderScrollbars( $scrollable[ 0 ] );
+
+ $scrollable[ 0 ].style.overflow = oldOverflow;
+ }, 300 );
+
+ return this;
};
/**
@@ -5733,15 +7765,15 @@ OO.ui.MessageDialog.prototype.initialize = function () {
OO.ui.MessageDialog.super.prototype.initialize.call( this );
// Properties
- this.$actions = this.$( '<div>' );
+ this.$actions = $( '<div>' );
this.container = new OO.ui.PanelLayout( {
- $: this.$, scrollable: true, classes: [ 'oo-ui-messageDialog-container' ]
+ scrollable: true, classes: [ 'oo-ui-messageDialog-container' ]
} );
this.text = new OO.ui.PanelLayout( {
- $: this.$, padded: true, expanded: false, classes: [ 'oo-ui-messageDialog-text' ]
+ padded: true, expanded: false, classes: [ 'oo-ui-messageDialog-text' ]
} );
this.message = new OO.ui.LabelWidget( {
- $: this.$, classes: [ 'oo-ui-messageDialog-message' ]
+ classes: [ 'oo-ui-messageDialog-message' ]
} );
// Initialization
@@ -5771,7 +7803,7 @@ OO.ui.MessageDialog.prototype.attachActions = function () {
}
if ( others.length ) {
for ( i = 0, len = others.length; i < len; i++ ) {
- other = others[i];
+ other = others[ i ];
this.$actions.append( other.$element );
other.toggleFramed( false );
}
@@ -5781,51 +7813,96 @@ OO.ui.MessageDialog.prototype.attachActions = function () {
special.primary.toggleFramed( false );
}
- this.fitActions();
if ( !this.isOpening() ) {
- this.manager.updateWindowSize( this );
+ // If the dialog is currently opening, this will be called automatically soon.
+ // This also calls #fitActions.
+ this.updateSize();
}
- this.$body.css( 'bottom', this.$foot.outerHeight( true ) );
};
/**
* Fit action actions into columns or rows.
*
* Columns will be used if all labels can fit without overflow, otherwise rows will be used.
+ *
+ * @private
*/
OO.ui.MessageDialog.prototype.fitActions = function () {
var i, len, action,
+ previous = this.verticalActionLayout,
actions = this.actions.get();
// Detect clipping
this.toggleVerticalActionLayout( false );
for ( i = 0, len = actions.length; i < len; i++ ) {
- action = actions[i];
+ action = actions[ i ];
if ( action.$element.innerWidth() < action.$label.outerWidth( true ) ) {
this.toggleVerticalActionLayout( true );
break;
}
}
-};
-/**
- * Navigation dialog window.
- *
- * Logic:
- * - Show and hide errors.
- * - Retry an action.
- *
- * User interface:
- * - Renders header with dialog title and one action widget on either side
- * (a 'safe' button on the left, and a 'primary' button on the right, both of
- * which close the dialog).
- * - Displays any action widgets in the footer (none by default).
- * - Ability to dismiss errors.
- *
- * Subclass responsibilities:
- * - Register a 'safe' action.
- * - Register a 'primary' action.
- * - Add content to the dialog.
+ // Move the body out of the way of the foot
+ this.$body.css( 'bottom', this.$foot.outerHeight( true ) );
+
+ if ( this.verticalActionLayout !== previous ) {
+ // We changed the layout, window height might need to be updated.
+ this.updateSize();
+ }
+};
+
+/**
+ * ProcessDialog windows encapsulate a {@link OO.ui.Process process} and all of the code necessary
+ * to complete it. If the process terminates with an error, a customizable {@link OO.ui.Error error
+ * interface} alerts users to the trouble, permitting the user to dismiss the error and try again when
+ * relevant. The ProcessDialog class is always extended and customized with the actions and content
+ * required for each process.
+ *
+ * The process dialog box consists of a header that visually represents the ‘working’ state of long
+ * processes with an animation. The header contains the dialog title as well as
+ * two {@link OO.ui.ActionWidget action widgets}: a ‘safe’ action on the left (e.g., ‘Cancel’) and
+ * a ‘primary’ action on the right (e.g., ‘Done’).
+ *
+ * Like other windows, the process dialog is managed by a {@link OO.ui.WindowManager window manager}.
+ * Please see the [OOjs UI documentation on MediaWiki][1] for more information and examples.
+ *
+ * @example
+ * // Example: Creating and opening a process dialog window.
+ * function MyProcessDialog( config ) {
+ * MyProcessDialog.super.call( this, config );
+ * }
+ * OO.inheritClass( MyProcessDialog, OO.ui.ProcessDialog );
+ *
+ * MyProcessDialog.static.title = 'Process dialog';
+ * MyProcessDialog.static.actions = [
+ * { action: 'save', label: 'Done', flags: 'primary' },
+ * { label: 'Cancel', flags: 'safe' }
+ * ];
+ *
+ * MyProcessDialog.prototype.initialize = function () {
+ * MyProcessDialog.super.prototype.initialize.apply( this, arguments );
+ * this.content = new OO.ui.PanelLayout( { padded: true, expanded: false } );
+ * this.content.$element.append( '<p>This is a process dialog window. The header contains the title and two buttons: \'Cancel\' (a safe action) on the left and \'Done\' (a primary action) on the right.</p>' );
+ * this.$body.append( this.content.$element );
+ * };
+ * MyProcessDialog.prototype.getActionProcess = function ( action ) {
+ * var dialog = this;
+ * if ( action ) {
+ * return new OO.ui.Process( function () {
+ * dialog.close( { action: action } );
+ * } );
+ * }
+ * return MyProcessDialog.super.prototype.getActionProcess.call( this, action );
+ * };
+ *
+ * var windowManager = new OO.ui.WindowManager();
+ * $( 'body' ).append( windowManager.$element );
+ *
+ * var dialog = new MyProcessDialog();
+ * windowManager.addWindows( [ dialog ] );
+ * windowManager.openWindow( dialog );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs
*
* @abstract
* @class
@@ -5852,6 +7929,8 @@ OO.inheritClass( OO.ui.ProcessDialog, OO.ui.Dialog );
* Handle dismiss button click events.
*
* Hides errors.
+ *
+ * @private
*/
OO.ui.ProcessDialog.prototype.onDismissErrorButtonClick = function () {
this.hideErrors();
@@ -5861,10 +7940,12 @@ OO.ui.ProcessDialog.prototype.onDismissErrorButtonClick = function () {
* Handle retry button click events.
*
* Hides errors and then tries again.
+ *
+ * @private
*/
OO.ui.ProcessDialog.prototype.onRetryButtonClick = function () {
this.hideErrors();
- this.executeAction( this.currentAction.getAction() );
+ this.executeAction( this.currentAction );
};
/**
@@ -5885,21 +7966,17 @@ OO.ui.ProcessDialog.prototype.initialize = function () {
OO.ui.ProcessDialog.super.prototype.initialize.call( this );
// Properties
- this.$navigation = this.$( '<div>' );
- this.$location = this.$( '<div>' );
- this.$safeActions = this.$( '<div>' );
- this.$primaryActions = this.$( '<div>' );
- this.$otherActions = this.$( '<div>' );
+ this.$navigation = $( '<div>' );
+ this.$location = $( '<div>' );
+ this.$safeActions = $( '<div>' );
+ this.$primaryActions = $( '<div>' );
+ this.$otherActions = $( '<div>' );
this.dismissButton = new OO.ui.ButtonWidget( {
- $: this.$,
label: OO.ui.msg( 'ooui-dialog-process-dismiss' )
} );
- this.retryButton = new OO.ui.ButtonWidget( {
- $: this.$,
- label: OO.ui.msg( 'ooui-dialog-process-retry' )
- } );
- this.$errors = this.$( '<div>' );
- this.$errorsTitle = this.$( '<div>' );
+ this.retryButton = new OO.ui.ButtonWidget();
+ this.$errors = $( '<div>' );
+ this.$errorsTitle = $( '<div>' );
// Events
this.dismissButton.connect( this, { click: 'onDismissErrorButtonClick' } );
@@ -5917,7 +7994,7 @@ OO.ui.ProcessDialog.prototype.initialize = function () {
.addClass( 'oo-ui-processDialog-errors-title' )
.text( OO.ui.msg( 'ooui-dialog-process-error' ) );
this.$errors
- .addClass( 'oo-ui-processDialog-errors' )
+ .addClass( 'oo-ui-processDialog-errors oo-ui-element-hidden' )
.append( this.$errorsTitle, this.dismissButton.$element, this.retryButton.$element );
this.$content
.addClass( 'oo-ui-processDialog-content' )
@@ -5932,6 +8009,19 @@ OO.ui.ProcessDialog.prototype.initialize = function () {
/**
* @inheritdoc
*/
+OO.ui.ProcessDialog.prototype.getActionWidgets = function ( actions ) {
+ var i, len, widgets = [];
+ for ( i = 0, len = actions.length; i < len; i++ ) {
+ widgets.push(
+ new OO.ui.ActionWidget( $.extend( { framed: true }, actions[ i ] ) )
+ );
+ }
+ return widgets;
+};
+
+/**
+ * @inheritdoc
+ */
OO.ui.ProcessDialog.prototype.attachActions = function () {
var i, len, other, special, others;
@@ -5942,18 +8032,13 @@ OO.ui.ProcessDialog.prototype.attachActions = function () {
others = this.actions.getOthers();
if ( special.primary ) {
this.$primaryActions.append( special.primary.$element );
- special.primary.toggleFramed( true );
}
- if ( others.length ) {
- for ( i = 0, len = others.length; i < len; i++ ) {
- other = others[i];
- this.$otherActions.append( other.$element );
- other.toggleFramed( true );
- }
+ for ( i = 0, len = others.length; i < len; i++ ) {
+ other = others[ i ];
+ this.$otherActions.append( other.$element );
}
if ( special.safe ) {
this.$safeActions.append( special.safe.$element );
- special.safe.toggleFramed( true );
}
this.fitLabel();
@@ -5964,13 +8049,17 @@ OO.ui.ProcessDialog.prototype.attachActions = function () {
* @inheritdoc
*/
OO.ui.ProcessDialog.prototype.executeAction = function ( action ) {
- OO.ui.ProcessDialog.super.prototype.executeAction.call( this, action )
- .fail( OO.ui.bind( this.showErrors, this ) );
+ var process = this;
+ return OO.ui.ProcessDialog.super.prototype.executeAction.call( this, action )
+ .fail( function ( errors ) {
+ process.showErrors( errors || [] );
+ } );
};
/**
* Fit label between actions.
*
+ * @private
* @chainable
*/
OO.ui.ProcessDialog.prototype.fitLabel = function () {
@@ -5984,59 +8073,740 @@ OO.ui.ProcessDialog.prototype.fitLabel = function () {
};
/**
- * Handle errors that occured durring accept or reject processes.
+ * Handle errors that occurred during accept or reject processes.
*
- * @param {OO.ui.Error[]} errors Errors to be handled
+ * @private
+ * @param {OO.ui.Error[]|OO.ui.Error} errors Errors to be handled
*/
OO.ui.ProcessDialog.prototype.showErrors = function ( errors ) {
- var i, len, $item,
+ var i, len, $item, actions,
items = [],
- recoverable = true;
+ abilities = {},
+ recoverable = true,
+ warning = false;
+
+ if ( errors instanceof OO.ui.Error ) {
+ errors = [ errors ];
+ }
for ( i = 0, len = errors.length; i < len; i++ ) {
- if ( !errors[i].isRecoverable() ) {
+ if ( !errors[ i ].isRecoverable() ) {
recoverable = false;
}
- $item = this.$( '<div>' )
+ if ( errors[ i ].isWarning() ) {
+ warning = true;
+ }
+ $item = $( '<div>' )
.addClass( 'oo-ui-processDialog-error' )
- .append( errors[i].getMessage() );
- items.push( $item[0] );
+ .append( errors[ i ].getMessage() );
+ items.push( $item[ 0 ] );
}
- this.$errorItems = this.$( items );
+ this.$errorItems = $( items );
if ( recoverable ) {
- this.retryButton.clearFlags().setFlags( this.currentAction.getFlags() );
+ abilities[this.currentAction] = true;
+ // Copy the flags from the first matching action
+ actions = this.actions.get( { actions: this.currentAction } );
+ if ( actions.length ) {
+ this.retryButton.clearFlags().setFlags( actions[0].getFlags() );
+ }
+ } else {
+ abilities[this.currentAction] = false;
+ this.actions.setAbilities( abilities );
+ }
+ if ( warning ) {
+ this.retryButton.setLabel( OO.ui.msg( 'ooui-dialog-process-continue' ) );
} else {
- this.currentAction.setDisabled( true );
+ this.retryButton.setLabel( OO.ui.msg( 'ooui-dialog-process-retry' ) );
}
this.retryButton.toggle( recoverable );
this.$errorsTitle.after( this.$errorItems );
- this.$errors.show().scrollTop( 0 );
+ this.$errors.removeClass( 'oo-ui-element-hidden' ).scrollTop( 0 );
};
/**
* Hide errors.
+ *
+ * @private
*/
OO.ui.ProcessDialog.prototype.hideErrors = function () {
- this.$errors.hide();
- this.$errorItems.remove();
- this.$errorItems = null;
+ this.$errors.addClass( 'oo-ui-element-hidden' );
+ if ( this.$errorItems ) {
+ this.$errorItems.remove();
+ this.$errorItems = null;
+ }
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.ProcessDialog.prototype.getTeardownProcess = function ( data ) {
+ // Parent method
+ return OO.ui.ProcessDialog.super.prototype.getTeardownProcess.call( this, data )
+ .first( function () {
+ // Make sure to hide errors
+ this.hideErrors();
+ }, this );
+};
+
+/**
+ * FieldLayouts are used with OO.ui.FieldsetLayout. Each FieldLayout requires a field-widget,
+ * which is a widget that is specified by reference before any optional configuration settings.
+ *
+ * Field layouts can be configured with help text and/or labels. Labels are aligned in one of four ways:
+ *
+ * - **left**: The label is placed before the field-widget and aligned with the left margin.
+ * A left-alignment is used for forms with many fields.
+ * - **right**: The label is placed before the field-widget and aligned to the right margin.
+ * A right-alignment is used for long but familiar forms which users tab through,
+ * verifying the current field with a quick glance at the label.
+ * - **top**: The label is placed above the field-widget. A top-alignment is used for brief forms
+ * that users fill out from top to bottom.
+ * - **inline**: The label is placed after the field-widget and aligned to the left.
+ * An inline-alignment is best used with checkboxes or radio buttons.
+ *
+ * Help text is accessed via a help icon that appears in the upper right corner of the rendered field layout.
+ * Please see the [OOjs UI documentation on MediaWiki] [1] for examples and more information.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Layouts/Fields_and_Fieldsets
+ * @class
+ * @extends OO.ui.Layout
+ * @mixins OO.ui.LabelElement
+ *
+ * @constructor
+ * @param {OO.ui.Widget} fieldWidget Field widget
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [align='left'] Alignment of the label: 'left', 'right', 'top' or 'inline'
+ * @cfg {string} [help] Help text. When help text is specified, a help icon will appear
+ * in the upper-right corner of the rendered field.
+ */
+OO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( fieldWidget ) && config === undefined ) {
+ config = fieldWidget;
+ fieldWidget = config.fieldWidget;
+ }
+
+ var hasInputWidget = fieldWidget instanceof OO.ui.InputWidget;
+
+ // Configuration initialization
+ config = $.extend( { align: 'left' }, config );
+
+ // Parent constructor
+ OO.ui.FieldLayout.super.call( this, config );
+
+ // Mixin constructors
+ OO.ui.LabelElement.call( this, config );
+
+ // Properties
+ this.fieldWidget = fieldWidget;
+ this.$field = $( '<div>' );
+ this.$body = $( '<' + ( hasInputWidget ? 'label' : 'div' ) + '>' );
+ this.align = null;
+ if ( config.help ) {
+ this.popupButtonWidget = new OO.ui.PopupButtonWidget( {
+ classes: [ 'oo-ui-fieldLayout-help' ],
+ framed: false,
+ icon: 'info'
+ } );
+
+ this.popupButtonWidget.getPopup().$body.append(
+ $( '<div>' )
+ .text( config.help )
+ .addClass( 'oo-ui-fieldLayout-help-content' )
+ );
+ this.$help = this.popupButtonWidget.$element;
+ } else {
+ this.$help = $( [] );
+ }
+
+ // Events
+ if ( hasInputWidget ) {
+ this.$label.on( 'click', this.onLabelClick.bind( this ) );
+ }
+ this.fieldWidget.connect( this, { disable: 'onFieldDisable' } );
+
+ // Initialization
+ this.$element
+ .addClass( 'oo-ui-fieldLayout' )
+ .append( this.$help, this.$body );
+ this.$body.addClass( 'oo-ui-fieldLayout-body' );
+ this.$field
+ .addClass( 'oo-ui-fieldLayout-field' )
+ .toggleClass( 'oo-ui-fieldLayout-disable', this.fieldWidget.isDisabled() )
+ .append( this.fieldWidget.$element );
+
+ this.setAlignment( config.align );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.FieldLayout, OO.ui.Layout );
+OO.mixinClass( OO.ui.FieldLayout, OO.ui.LabelElement );
+
+/* Methods */
+
+/**
+ * Handle field disable events.
+ *
+ * @private
+ * @param {boolean} value Field is disabled
+ */
+OO.ui.FieldLayout.prototype.onFieldDisable = function ( value ) {
+ this.$element.toggleClass( 'oo-ui-fieldLayout-disabled', value );
+};
+
+/**
+ * Handle label mouse click events.
+ *
+ * @private
+ * @param {jQuery.Event} e Mouse click event
+ */
+OO.ui.FieldLayout.prototype.onLabelClick = function () {
+ this.fieldWidget.simulateLabelClick();
+ return false;
+};
+
+/**
+ * Get the widget contained by the field.
+ *
+ * @return {OO.ui.Widget} Field widget
+ */
+OO.ui.FieldLayout.prototype.getField = function () {
+ return this.fieldWidget;
+};
+
+/**
+ * Set the field alignment mode.
+ *
+ * @private
+ * @param {string} value Alignment mode, either 'left', 'right', 'top' or 'inline'
+ * @chainable
+ */
+OO.ui.FieldLayout.prototype.setAlignment = function ( value ) {
+ if ( value !== this.align ) {
+ // Default to 'left'
+ if ( [ 'left', 'right', 'top', 'inline' ].indexOf( value ) === -1 ) {
+ value = 'left';
+ }
+ // Reorder elements
+ if ( value === 'inline' ) {
+ this.$body.append( this.$field, this.$label );
+ } else {
+ this.$body.append( this.$label, this.$field );
+ }
+ // Set classes. The following classes can be used here:
+ // * oo-ui-fieldLayout-align-left
+ // * oo-ui-fieldLayout-align-right
+ // * oo-ui-fieldLayout-align-top
+ // * oo-ui-fieldLayout-align-inline
+ if ( this.align ) {
+ this.$element.removeClass( 'oo-ui-fieldLayout-align-' + this.align );
+ }
+ this.$element.addClass( 'oo-ui-fieldLayout-align-' + value );
+ this.align = value;
+ }
+
+ return this;
+};
+
+/**
+ * ActionFieldLayouts are used with OO.ui.FieldsetLayout. The layout consists of a field-widget, a button,
+ * and an optional label and/or help text. The field-widget (e.g., a {@link OO.ui.TextInputWidget TextInputWidget}),
+ * is required and is specified before any optional configuration settings.
+ *
+ * Labels can be aligned in one of four ways:
+ *
+ * - **left**: The label is placed before the field-widget and aligned with the left margin.
+ * A left-alignment is used for forms with many fields.
+ * - **right**: The label is placed before the field-widget and aligned to the right margin.
+ * A right-alignment is used for long but familiar forms which users tab through,
+ * verifying the current field with a quick glance at the label.
+ * - **top**: The label is placed above the field-widget. A top-alignment is used for brief forms
+ * that users fill out from top to bottom.
+ * - **inline**: The label is placed after the field-widget and aligned to the left.
+ * An inline-alignment is best used with checkboxes or radio buttons.
+ *
+ * Help text is accessed via a help icon that appears in the upper right corner of the rendered field layout when help
+ * text is specified.
+ *
+ * @example
+ * // Example of an ActionFieldLayout
+ * var actionFieldLayout = new OO.ui.ActionFieldLayout(
+ * new OO.ui.TextInputWidget( {
+ * placeholder: 'Field widget'
+ * } ),
+ * new OO.ui.ButtonWidget( {
+ * label: 'Button'
+ * } ),
+ * {
+ * label: 'An ActionFieldLayout. This label is aligned top',
+ * align: 'top',
+ * help: 'This is help text'
+ * }
+ * );
+ *
+ * $( 'body' ).append( actionFieldLayout.$element );
+ *
+ *
+ * @class
+ * @extends OO.ui.FieldLayout
+ *
+ * @constructor
+ * @param {OO.ui.Widget} fieldWidget Field widget
+ * @param {OO.ui.ButtonWidget} buttonWidget Button widget
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [align='left'] Alignment of the label: 'left', 'right', 'top' or 'inline'
+ * @cfg {string} [help] Help text. When help text is specified, a help icon will appear in the
+ * upper-right corner of the rendered field.
+ */
+OO.ui.ActionFieldLayout = function OoUiActionFieldLayout( fieldWidget, buttonWidget, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( fieldWidget ) && config === undefined ) {
+ config = fieldWidget;
+ fieldWidget = config.fieldWidget;
+ buttonWidget = config.buttonWidget;
+ }
+
+ // Configuration initialization
+ config = $.extend( { align: 'left' }, config );
+
+ // Parent constructor
+ OO.ui.ActionFieldLayout.super.call( this, fieldWidget, config );
+
+ // Properties
+ this.fieldWidget = fieldWidget;
+ this.buttonWidget = buttonWidget;
+ this.$button = $( '<div>' )
+ .addClass( 'oo-ui-actionFieldLayout-button' )
+ .append( this.buttonWidget.$element );
+ this.$input = $( '<div>' )
+ .addClass( 'oo-ui-actionFieldLayout-input' )
+ .append( this.fieldWidget.$element );
+ this.$field
+ .addClass( 'oo-ui-actionFieldLayout' )
+ .append( this.$input, this.$button );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.ActionFieldLayout, OO.ui.FieldLayout );
+
+/**
+ * FieldsetLayouts are composed of one or more {@link OO.ui.FieldLayout FieldLayouts},
+ * which each contain an individual widget and, optionally, a label. Each Fieldset can be
+ * configured with a label as well. For more information and examples,
+ * please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * @example
+ * // Example of a fieldset layout
+ * var input1 = new OO.ui.TextInputWidget( {
+ * placeholder: 'A text input field'
+ * } );
+ *
+ * var input2 = new OO.ui.TextInputWidget( {
+ * placeholder: 'A text input field'
+ * } );
+ *
+ * var fieldset = new OO.ui.FieldsetLayout( {
+ * label: 'Example of a fieldset layout'
+ * } );
+ *
+ * fieldset.addItems( [
+ * new OO.ui.FieldLayout( input1, {
+ * label: 'Field One'
+ * } ),
+ * new OO.ui.FieldLayout( input2, {
+ * label: 'Field Two'
+ * } )
+ * ] );
+ * $( 'body' ).append( fieldset.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Layouts/Fields_and_Fieldsets
+ *
+ * @class
+ * @extends OO.ui.Layout
+ * @mixins OO.ui.IconElement
+ * @mixins OO.ui.LabelElement
+ * @mixins OO.ui.GroupElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {OO.ui.FieldLayout[]} [items] An array of fields to add to the fieldset. See OO.ui.FieldLayout for more information about fields.
+ */
+OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.FieldsetLayout.super.call( this, config );
+
+ // Mixin constructors
+ OO.ui.IconElement.call( this, config );
+ OO.ui.LabelElement.call( this, config );
+ OO.ui.GroupElement.call( this, config );
+
+ if ( config.help ) {
+ this.popupButtonWidget = new OO.ui.PopupButtonWidget( {
+ classes: [ 'oo-ui-fieldsetLayout-help' ],
+ framed: false,
+ icon: 'info'
+ } );
+
+ this.popupButtonWidget.getPopup().$body.append(
+ $( '<div>' )
+ .text( config.help )
+ .addClass( 'oo-ui-fieldsetLayout-help-content' )
+ );
+ this.$help = this.popupButtonWidget.$element;
+ } else {
+ this.$help = $( [] );
+ }
+
+ // Initialization
+ this.$element
+ .addClass( 'oo-ui-fieldsetLayout' )
+ .prepend( this.$help, this.$icon, this.$label, this.$group );
+ if ( Array.isArray( config.items ) ) {
+ this.addItems( config.items );
+ }
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.FieldsetLayout, OO.ui.Layout );
+OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.IconElement );
+OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.LabelElement );
+OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.GroupElement );
+
+/**
+ * FormLayouts are used to wrap {@link OO.ui.FieldsetLayout FieldsetLayouts} when you intend to use browser-based
+ * form submission for the fields instead of handling them in JavaScript. Form layouts can be configured with an
+ * HTML form action, an encoding type, and a method using the #action, #enctype, and #method configs, respectively.
+ * See the [OOjs UI documentation on MediaWiki] [1] for more information and examples.
+ *
+ * Only widgets from the {@link OO.ui.InputWidget InputWidget} family support form submission. It
+ * includes standard form elements like {@link OO.ui.CheckboxInputWidget checkboxes}, {@link
+ * OO.ui.RadioInputWidget radio buttons} and {@link OO.ui.TextInputWidget text fields}, as well as
+ * some fancier controls. Some controls have both regular and InputWidget variants, for example
+ * OO.ui.DropdownWidget and OO.ui.DropdownInputWidget – only the latter support form submission and
+ * often have simplified APIs to match the capabilities of HTML forms.
+ * See the [OOjs UI Inputs documentation on MediaWiki] [2] for more information about InputWidgets.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Layouts/Forms
+ * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
+ *
+ * @example
+ * // Example of a form layout that wraps a fieldset layout
+ * var input1 = new OO.ui.TextInputWidget( {
+ * placeholder: 'Username'
+ * } );
+ * var input2 = new OO.ui.TextInputWidget( {
+ * placeholder: 'Password',
+ * type: 'password'
+ * } );
+ * var submit = new OO.ui.ButtonInputWidget( {
+ * label: 'Submit'
+ * } );
+ *
+ * var fieldset = new OO.ui.FieldsetLayout( {
+ * label: 'A form layout'
+ * } );
+ * fieldset.addItems( [
+ * new OO.ui.FieldLayout( input1, {
+ * label: 'Username',
+ * align: 'top'
+ * } ),
+ * new OO.ui.FieldLayout( input2, {
+ * label: 'Password',
+ * align: 'top'
+ * } ),
+ * new OO.ui.FieldLayout( submit )
+ * ] );
+ * var form = new OO.ui.FormLayout( {
+ * items: [ fieldset ],
+ * action: '/api/formhandler',
+ * method: 'get'
+ * } )
+ * $( 'body' ).append( form.$element );
+ *
+ * @class
+ * @extends OO.ui.Layout
+ * @mixins OO.ui.GroupElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [method] HTML form `method` attribute
+ * @cfg {string} [action] HTML form `action` attribute
+ * @cfg {string} [enctype] HTML form `enctype` attribute
+ * @cfg {OO.ui.FieldsetLayout[]} [items] Fieldset layouts to add to the form layout.
+ */
+OO.ui.FormLayout = function OoUiFormLayout( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.FormLayout.super.call( this, config );
+
+ // Mixin constructors
+ OO.ui.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
+
+ // Events
+ this.$element.on( 'submit', this.onFormSubmit.bind( this ) );
+
+ // Initialization
+ this.$element
+ .addClass( 'oo-ui-formLayout' )
+ .attr( {
+ method: config.method,
+ action: config.action,
+ enctype: config.enctype
+ } );
+ if ( Array.isArray( config.items ) ) {
+ this.addItems( config.items );
+ }
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.FormLayout, OO.ui.Layout );
+OO.mixinClass( OO.ui.FormLayout, OO.ui.GroupElement );
+
+/* Events */
+
+/**
+ * A 'submit' event is emitted when the form is submitted.
+ *
+ * @event submit
+ */
+
+/* Static Properties */
+
+OO.ui.FormLayout.static.tagName = 'form';
+
+/* Methods */
+
+/**
+ * Handle form submit events.
+ *
+ * @private
+ * @param {jQuery.Event} e Submit event
+ * @fires submit
+ */
+OO.ui.FormLayout.prototype.onFormSubmit = function () {
+ if ( this.emit( 'submit' ) ) {
+ return false;
+ }
};
/**
- * Layout containing a series of pages.
+ * MenuLayouts combine a menu and a content {@link OO.ui.PanelLayout panel}. The menu is positioned relative to the content (after, before, top, or bottom)
+ * and its size is customized with the #menuSize config. The content area will fill all remaining space.
+ *
+ * @example
+ * var menuLayout = new OO.ui.MenuLayout( {
+ * position: 'top'
+ * } ),
+ * menuPanel = new OO.ui.PanelLayout( { padded: true, expanded: true, scrollable: true } ),
+ * contentPanel = new OO.ui.PanelLayout( { padded: true, expanded: true, scrollable: true } ),
+ * select = new OO.ui.SelectWidget( {
+ * items: [
+ * new OO.ui.OptionWidget( {
+ * data: 'before',
+ * label: 'Before',
+ * } ),
+ * new OO.ui.OptionWidget( {
+ * data: 'after',
+ * label: 'After',
+ * } ),
+ * new OO.ui.OptionWidget( {
+ * data: 'top',
+ * label: 'Top',
+ * } ),
+ * new OO.ui.OptionWidget( {
+ * data: 'bottom',
+ * label: 'Bottom',
+ * } )
+ * ]
+ * } ).on( 'select', function ( item ) {
+ * menuLayout.setMenuPosition( item.getData() );
+ * } );
+ *
+ * menuLayout.$menu.append(
+ * menuPanel.$element.append( '<b>Menu panel</b>', select.$element )
+ * );
+ * menuLayout.$content.append(
+ * contentPanel.$element.append( '<b>Content panel</b>', '<p>Note that the menu is positioned relative to the content panel: top, bottom, after, before.</p>')
+ * );
+ * $( 'body' ).append( menuLayout.$element );
+ *
+ * If menu size needs to be overridden, it can be accomplished using CSS similar to the snippet
+ * below. MenuLayout's CSS will override the appropriate values with 'auto' or '0' to display the
+ * menu correctly. If `menuPosition` is known beforehand, CSS rules corresponding to other positions
+ * may be omitted.
+ *
+ * .oo-ui-menuLayout-menu {
+ * height: 200px;
+ * width: 200px;
+ * }
+ * .oo-ui-menuLayout-content {
+ * top: 200px;
+ * left: 200px;
+ * right: 200px;
+ * bottom: 200px;
+ * }
*
* @class
* @extends OO.ui.Layout
*
* @constructor
* @param {Object} [config] Configuration options
+ * @cfg {boolean} [showMenu=true] Show menu
+ * @cfg {string} [menuPosition='before'] Position of menu: `top`, `after`, `bottom` or `before`
+ */
+OO.ui.MenuLayout = function OoUiMenuLayout( config ) {
+ // Configuration initialization
+ config = $.extend( {
+ showMenu: true,
+ menuPosition: 'before'
+ }, config );
+
+ // Parent constructor
+ OO.ui.MenuLayout.super.call( this, config );
+
+ /**
+ * Menu DOM node
+ *
+ * @property {jQuery}
+ */
+ this.$menu = $( '<div>' );
+ /**
+ * Content DOM node
+ *
+ * @property {jQuery}
+ */
+ this.$content = $( '<div>' );
+
+ // Initialization
+ this.$menu
+ .addClass( 'oo-ui-menuLayout-menu' );
+ this.$content.addClass( 'oo-ui-menuLayout-content' );
+ this.$element
+ .addClass( 'oo-ui-menuLayout' )
+ .append( this.$content, this.$menu );
+ this.setMenuPosition( config.menuPosition );
+ this.toggleMenu( config.showMenu );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.MenuLayout, OO.ui.Layout );
+
+/* Methods */
+
+/**
+ * Toggle menu.
+ *
+ * @param {boolean} showMenu Show menu, omit to toggle
+ * @chainable
+ */
+OO.ui.MenuLayout.prototype.toggleMenu = function ( showMenu ) {
+ showMenu = showMenu === undefined ? !this.showMenu : !!showMenu;
+
+ if ( this.showMenu !== showMenu ) {
+ this.showMenu = showMenu;
+ this.$element
+ .toggleClass( 'oo-ui-menuLayout-showMenu', this.showMenu )
+ .toggleClass( 'oo-ui-menuLayout-hideMenu', !this.showMenu );
+ }
+
+ return this;
+};
+
+/**
+ * Check if menu is visible
+ *
+ * @return {boolean} Menu is visible
+ */
+OO.ui.MenuLayout.prototype.isMenuVisible = function () {
+ return this.showMenu;
+};
+
+/**
+ * Set menu position.
+ *
+ * @param {string} position Position of menu, either `top`, `after`, `bottom` or `before`
+ * @throws {Error} If position value is not supported
+ * @chainable
+ */
+OO.ui.MenuLayout.prototype.setMenuPosition = function ( position ) {
+ this.$element.removeClass( 'oo-ui-menuLayout-' + this.menuPosition );
+ this.menuPosition = position;
+ this.$element.addClass( 'oo-ui-menuLayout-' + position );
+
+ return this;
+};
+
+/**
+ * Get menu position.
+ *
+ * @return {string} Menu position
+ */
+OO.ui.MenuLayout.prototype.getMenuPosition = function () {
+ return this.menuPosition;
+};
+
+/**
+ * BookletLayouts contain {@link OO.ui.PageLayout page layouts} as well as
+ * an {@link OO.ui.OutlineSelectWidget outline} that allows users to easily navigate
+ * through the pages and select which one to display. By default, only one page is
+ * displayed at a time and the outline is hidden. When a user navigates to a new page,
+ * the booklet layout automatically focuses on the first focusable element, unless the
+ * default setting is changed. Optionally, booklets can be configured to show
+ * {@link OO.ui.OutlineControlsWidget controls} for adding, moving, and removing items.
+ *
+ * @example
+ * // Example of a BookletLayout that contains two PageLayouts.
+ *
+ * function PageOneLayout( name, config ) {
+ * PageOneLayout.super.call( this, name, config );
+ * this.$element.append( '<p>First page</p><p>(This booklet has an outline, displayed on the left)</p>' );
+ * }
+ * OO.inheritClass( PageOneLayout, OO.ui.PageLayout );
+ * PageOneLayout.prototype.setupOutlineItem = function () {
+ * this.outlineItem.setLabel( 'Page One' );
+ * };
+ *
+ * function PageTwoLayout( name, config ) {
+ * PageTwoLayout.super.call( this, name, config );
+ * this.$element.append( '<p>Second page</p>' );
+ * }
+ * OO.inheritClass( PageTwoLayout, OO.ui.PageLayout );
+ * PageTwoLayout.prototype.setupOutlineItem = function () {
+ * this.outlineItem.setLabel( 'Page Two' );
+ * };
+ *
+ * var page1 = new PageOneLayout( 'one' ),
+ * page2 = new PageTwoLayout( 'two' );
+ *
+ * var booklet = new OO.ui.BookletLayout( {
+ * outlined: true
+ * } );
+ *
+ * booklet.addPages ( [ page1, page2 ] );
+ * $( 'body' ).append( booklet.$element );
+ *
+ * @class
+ * @extends OO.ui.MenuLayout
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
* @cfg {boolean} [continuous=false] Show all pages, one after another
- * @cfg {boolean} [autoFocus=true] Focus on the first focusable element when changing to a page
- * @cfg {boolean} [outlined=false] Show an outline
+ * @cfg {boolean} [autoFocus=true] Focus on the first focusable element when a new page is displayed.
+ * @cfg {boolean} [outlined=false] Show the outline. The outline is used to navigate through the pages of the booklet.
* @cfg {boolean} [editable=false] Show controls for adding, removing and reordering pages
*/
OO.ui.BookletLayout = function OoUiBookletLayout( config ) {
- // Initialize configuration
+ // Configuration initialization
config = config || {};
// Parent constructor
@@ -6046,35 +8816,34 @@ OO.ui.BookletLayout = function OoUiBookletLayout( config ) {
this.currentPageName = null;
this.pages = {};
this.ignoreFocus = false;
- this.stackLayout = new OO.ui.StackLayout( { $: this.$, continuous: !!config.continuous } );
+ this.stackLayout = new OO.ui.StackLayout( { continuous: !!config.continuous } );
+ this.$content.append( this.stackLayout.$element );
this.autoFocus = config.autoFocus === undefined || !!config.autoFocus;
this.outlineVisible = false;
this.outlined = !!config.outlined;
if ( this.outlined ) {
this.editable = !!config.editable;
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 ] }
- );
+ this.outlineSelectWidget = new OO.ui.OutlineSelectWidget();
+ this.outlinePanel = new OO.ui.PanelLayout( { scrollable: true } );
+ this.$menu.append( this.outlinePanel.$element );
this.outlineVisible = true;
if ( this.editable ) {
this.outlineControlsWidget = new OO.ui.OutlineControlsWidget(
- this.outlineWidget, { $: this.$ }
+ this.outlineSelectWidget
);
}
}
+ this.toggleMenu( this.outlined );
// Events
this.stackLayout.connect( this, { set: 'onStackLayoutSet' } );
if ( this.outlined ) {
- this.outlineWidget.connect( this, { select: 'onOutlineWidgetSelect' } );
+ this.outlineSelectWidget.connect( this, { select: 'onOutlineSelectWidgetSelect' } );
}
if ( this.autoFocus ) {
// Event 'focus' does not bubble, but 'focusin' does
- this.stackLayout.onDOMEvent( 'focusin', OO.ui.bind( this.onStackLayoutFocus, this ) );
+ this.stackLayout.$element.on( 'focusin', this.onStackLayoutFocus.bind( this ) );
}
// Initialization
@@ -6083,36 +8852,39 @@ OO.ui.BookletLayout = function OoUiBookletLayout( config ) {
if ( this.outlined ) {
this.outlinePanel.$element
.addClass( 'oo-ui-bookletLayout-outlinePanel' )
- .append( this.outlineWidget.$element );
+ .append( this.outlineSelectWidget.$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 );
}
};
/* Setup */
-OO.inheritClass( OO.ui.BookletLayout, OO.ui.Layout );
+OO.inheritClass( OO.ui.BookletLayout, OO.ui.MenuLayout );
/* Events */
/**
+ * A 'set' event is emitted when a page is {@link #setPage set} to be displayed by the booklet layout.
* @event set
* @param {OO.ui.PageLayout} page Current page
*/
/**
+ * An 'add' event is emitted when pages are {@link #addPages added} to the booklet layout.
+ *
* @event add
* @param {OO.ui.PageLayout[]} page Added pages
* @param {number} index Index pages were added at
*/
/**
+ * A 'remove' event is emitted when pages are {@link #clearPages cleared} or
+ * {@link #removePages removed} from the booklet.
+ *
* @event remove
* @param {OO.ui.PageLayout[]} pages Removed pages
*/
@@ -6122,6 +8894,7 @@ OO.inheritClass( OO.ui.BookletLayout, OO.ui.Layout );
/**
* Handle stack layout focus.
*
+ * @private
* @param {jQuery.Event} e Focusin event
*/
OO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) {
@@ -6131,7 +8904,7 @@ OO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) {
$target = $( e.target ).closest( '.oo-ui-pageLayout' );
for ( name in this.pages ) {
// Check for page match, exclude current page to find only page changes
- if ( this.pages[name].$element[0] === $target[0] && name !== this.currentPageName ) {
+ if ( this.pages[ name ].$element[ 0 ] === $target[ 0 ] && name !== this.currentPageName ) {
this.setPage( name );
break;
}
@@ -6141,31 +8914,89 @@ OO.ui.BookletLayout.prototype.onStackLayoutFocus = function ( e ) {
/**
* Handle stack layout set events.
*
+ * @private
* @param {OO.ui.PanelLayout|null} page The page panel that is now the current panel
*/
OO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) {
- var $input, layout = this;
+ var layout = this;
if ( page ) {
page.scrollElementIntoView( { complete: function () {
if ( layout.autoFocus ) {
- // Set focus to the first input if nothing on the page is focused yet
- if ( !page.$element.find( ':focus' ).length ) {
- $input = page.$element.find( ':input:first' );
- if ( $input.length ) {
- $input[0].focus();
- }
- }
+ layout.focus();
}
} } );
}
};
/**
+ * Focus the first input in the current page.
+ *
+ * If no page is selected, the first selectable page will be selected.
+ * If the focus is already in an element on the current page, nothing will happen.
+ * @param {number} [itemIndex] A specific item to focus on
+ */
+OO.ui.BookletLayout.prototype.focus = function ( itemIndex ) {
+ var $input, page,
+ items = this.stackLayout.getItems();
+
+ if ( itemIndex !== undefined && items[ itemIndex ] ) {
+ page = items[ itemIndex ];
+ } else {
+ page = this.stackLayout.getCurrentItem();
+ }
+
+ if ( !page && this.outlined ) {
+ this.selectFirstSelectablePage();
+ page = this.stackLayout.getCurrentItem();
+ }
+ if ( !page ) {
+ return;
+ }
+ // Only change the focus if is not already in the current page
+ if ( !page.$element.find( ':focus' ).length ) {
+ $input = page.$element.find( ':input:first' );
+ if ( $input.length ) {
+ $input[ 0 ].focus();
+ }
+ }
+};
+
+/**
+ * Find the first focusable input in the booklet layout and focus
+ * on it.
+ */
+OO.ui.BookletLayout.prototype.focusFirstFocusable = function () {
+ var i, len,
+ found = false,
+ items = this.stackLayout.getItems(),
+ checkAndFocus = function () {
+ if ( OO.ui.isFocusableElement( $( this ) ) ) {
+ $( this ).focus();
+ found = true;
+ return false;
+ }
+ };
+
+ for ( i = 0, len = items.length; i < len; i++ ) {
+ if ( found ) {
+ break;
+ }
+ // Find all potentially focusable elements in the item
+ // and check if they are focusable
+ items[i].$element
+ .find( 'input, select, textarea, button, object' )
+ /* jshint loopfunc:true */
+ .each( checkAndFocus );
+ }
+};
+
+/**
* Handle outline widget select events.
*
+ * @private
* @param {OO.ui.OptionWidget|null} item Selected item
*/
-OO.ui.BookletLayout.prototype.onOutlineWidgetSelect = function ( item ) {
+OO.ui.BookletLayout.prototype.onOutlineSelectWidgetSelect = function ( item ) {
if ( item ) {
this.setPage( item.getData() );
}
@@ -6174,7 +9005,7 @@ OO.ui.BookletLayout.prototype.onOutlineWidgetSelect = function ( item ) {
/**
* Check if booklet has an outline.
*
- * @return {boolean}
+ * @return {boolean} Booklet has an outline
*/
OO.ui.BookletLayout.prototype.isOutlined = function () {
return this.outlined;
@@ -6183,7 +9014,7 @@ OO.ui.BookletLayout.prototype.isOutlined = function () {
/**
* Check if booklet has editing controls.
*
- * @return {boolean}
+ * @return {boolean} Booklet is editable
*/
OO.ui.BookletLayout.prototype.isEditable = function () {
return this.editable;
@@ -6192,7 +9023,7 @@ OO.ui.BookletLayout.prototype.isEditable = function () {
/**
* Check if booklet has a visible outline.
*
- * @return {boolean}
+ * @return {boolean} Outline is visible
*/
OO.ui.BookletLayout.prototype.isOutlineVisible = function () {
return this.outlined && this.outlineVisible;
@@ -6208,17 +9039,17 @@ OO.ui.BookletLayout.prototype.toggleOutline = function ( show ) {
if ( this.outlined ) {
show = show === undefined ? !this.outlineVisible : !!show;
this.outlineVisible = show;
- this.gridLayout.layout( show ? [ 1, 2 ] : [ 0, 1 ], [ 1 ] );
+ this.toggleMenu( show );
}
return this;
};
/**
- * Get the outline widget.
+ * Get the page closest to the specified page.
*
- * @param {OO.ui.PageLayout} page Page to be selected
- * @return {OO.ui.PageLayout|null} Closest page to another
+ * @param {OO.ui.PageLayout} page Page to use as a reference point
+ * @return {OO.ui.PageLayout|null} Page closest to the specified page
*/
OO.ui.BookletLayout.prototype.getClosestPage = function ( page ) {
var next, prev, level,
@@ -6226,20 +9057,20 @@ OO.ui.BookletLayout.prototype.getClosestPage = function ( page ) {
index = $.inArray( page, pages );
if ( index !== -1 ) {
- next = pages[index + 1];
- prev = pages[index - 1];
+ next = pages[ index + 1 ];
+ prev = pages[ index - 1 ];
// Prefer adjacent pages at the same level
if ( this.outlined ) {
- level = this.outlineWidget.getItemFromData( page.getName() ).getLevel();
+ level = this.outlineSelectWidget.getItemFromData( page.getName() ).getLevel();
if (
prev &&
- level === this.outlineWidget.getItemFromData( prev.getName() ).getLevel()
+ level === this.outlineSelectWidget.getItemFromData( prev.getName() ).getLevel()
) {
return prev;
}
if (
next &&
- level === this.outlineWidget.getItemFromData( next.getName() ).getLevel()
+ level === this.outlineSelectWidget.getItemFromData( next.getName() ).getLevel()
) {
return next;
}
@@ -6251,14 +9082,18 @@ OO.ui.BookletLayout.prototype.getClosestPage = function ( page ) {
/**
* Get the outline widget.
*
- * @return {OO.ui.OutlineWidget|null} Outline widget, or null if boolet has no outline
+ * If the booklet is not outlined, the method will return `null`.
+ *
+ * @return {OO.ui.OutlineSelectWidget|null} Outline widget, or null if the booklet is not outlined
*/
OO.ui.BookletLayout.prototype.getOutline = function () {
- return this.outlineWidget;
+ return this.outlineSelectWidget;
};
/**
- * Get the outline controls widget. If the outline is not editable, null is returned.
+ * Get the outline controls widget.
+ *
+ * If the outline is not editable, the method will return `null`.
*
* @return {OO.ui.OutlineControlsWidget|null} The outline controls widget.
*/
@@ -6267,32 +9102,42 @@ OO.ui.BookletLayout.prototype.getOutlineControls = function () {
};
/**
- * Get a page by name.
+ * Get a page by its symbolic name.
*
* @param {string} name Symbolic name of page
* @return {OO.ui.PageLayout|undefined} Page, if found
*/
OO.ui.BookletLayout.prototype.getPage = function ( name ) {
- return this.pages[name];
+ return this.pages[ name ];
};
/**
- * Get the current page name.
+ * Get the current page.
*
- * @return {string|null} Current page name
+ * @return {OO.ui.PageLayout|undefined} Current page, if found
*/
-OO.ui.BookletLayout.prototype.getPageName = function () {
+OO.ui.BookletLayout.prototype.getCurrentPage = function () {
+ var name = this.getCurrentPageName();
+ return name ? this.getPage( name ) : undefined;
+};
+
+/**
+ * Get the symbolic name of the current page.
+ *
+ * @return {string|null} Symbolic name of the current page
+ */
+OO.ui.BookletLayout.prototype.getCurrentPageName = function () {
return this.currentPageName;
};
/**
- * Add a page to the layout.
+ * Add pages to the booklet 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.
*
* @param {OO.ui.PageLayout[]} pages Pages to add
- * @param {number} index Index to insert pages after
+ * @param {number} index Index of the insertion point
* @fires add
* @chainable
*/
@@ -6304,16 +9149,16 @@ OO.ui.BookletLayout.prototype.addPages = function ( pages, index ) {
// Remove pages with same names
for ( i = 0, len = pages.length; i < len; i++ ) {
- page = pages[i];
+ page = pages[ i ];
name = page.getName();
if ( Object.prototype.hasOwnProperty.call( this.pages, name ) ) {
// Correct the insertion index
- currentIndex = $.inArray( this.pages[name], stackLayoutPages );
+ currentIndex = $.inArray( this.pages[ name ], stackLayoutPages );
if ( currentIndex !== -1 && currentIndex + 1 < index ) {
index--;
}
- remove.push( this.pages[name] );
+ remove.push( this.pages[ name ] );
}
}
if ( remove.length ) {
@@ -6322,19 +9167,19 @@ OO.ui.BookletLayout.prototype.addPages = function ( pages, index ) {
// Add new pages
for ( i = 0, len = pages.length; i < len; i++ ) {
- page = pages[i];
+ page = pages[ i ];
name = page.getName();
- this.pages[page.getName()] = page;
+ this.pages[ page.getName() ] = page;
if ( this.outlined ) {
- item = new OO.ui.OutlineItemWidget( name, page, { $: this.$ } );
+ item = new OO.ui.OutlineOptionWidget( { data: name } );
page.setOutlineItem( item );
items.push( item );
}
}
if ( this.outlined && items.length ) {
- this.outlineWidget.addItems( items, index );
- this.updateOutlineWidget();
+ this.outlineSelectWidget.addItems( items, index );
+ this.selectFirstSelectablePage();
}
this.stackLayout.addItems( pages, index );
this.emit( 'add', pages, index );
@@ -6343,8 +9188,11 @@ OO.ui.BookletLayout.prototype.addPages = function ( pages, index ) {
};
/**
- * Remove a page from the layout.
+ * Remove the specified pages from the booklet layout.
+ *
+ * To remove all pages from the booklet, you may wish to use the #clearPages method instead.
*
+ * @param {OO.ui.PageLayout[]} pages An array of pages to remove
* @fires remove
* @chainable
*/
@@ -6353,17 +9201,17 @@ OO.ui.BookletLayout.prototype.removePages = function ( pages ) {
items = [];
for ( i = 0, len = pages.length; i < len; i++ ) {
- page = pages[i];
+ page = pages[ i ];
name = page.getName();
- delete this.pages[name];
+ delete this.pages[ name ];
if ( this.outlined ) {
- items.push( this.outlineWidget.getItemFromData( name ) );
+ items.push( this.outlineSelectWidget.getItemFromData( name ) );
page.setOutlineItem( null );
}
}
if ( this.outlined && items.length ) {
- this.outlineWidget.removeItems( items );
- this.updateOutlineWidget();
+ this.outlineSelectWidget.removeItems( items );
+ this.selectFirstSelectablePage();
}
this.stackLayout.removeItems( pages );
this.emit( 'remove', pages );
@@ -6372,7 +9220,9 @@ OO.ui.BookletLayout.prototype.removePages = function ( pages ) {
};
/**
- * Clear all pages from the layout.
+ * Clear all pages from the booklet layout.
+ *
+ * To remove only a subset of pages from the booklet, use the #removePages method.
*
* @fires remove
* @chainable
@@ -6384,9 +9234,9 @@ OO.ui.BookletLayout.prototype.clearPages = function () {
this.pages = {};
this.currentPageName = null;
if ( this.outlined ) {
- this.outlineWidget.clearItems();
+ this.outlineSelectWidget.clearItems();
for ( i = 0, len = pages.length; i < len; i++ ) {
- pages[i].setOutlineItem( null );
+ pages[ i ].setOutlineItem( null );
}
}
this.stackLayout.clearItems();
@@ -6397,7 +9247,7 @@ OO.ui.BookletLayout.prototype.clearPages = function () {
};
/**
- * Set the current page by name.
+ * Set the current page by symbolic name.
*
* @fires set
* @param {string} name Symbolic name of page
@@ -6405,25 +9255,25 @@ OO.ui.BookletLayout.prototype.clearPages = function () {
OO.ui.BookletLayout.prototype.setPage = function ( name ) {
var selectedItem,
$focused,
- page = this.pages[name];
+ page = this.pages[ name ];
if ( name !== this.currentPageName ) {
if ( this.outlined ) {
- selectedItem = this.outlineWidget.getSelectedItem();
+ selectedItem = this.outlineSelectWidget.getSelectedItem();
if ( selectedItem && selectedItem.getData() !== name ) {
- this.outlineWidget.selectItem( this.outlineWidget.getItemFromData( name ) );
+ this.outlineSelectWidget.selectItemByData( name );
}
}
if ( page ) {
- if ( this.currentPageName && this.pages[this.currentPageName] ) {
- this.pages[this.currentPageName].setActive( false );
+ if ( this.currentPageName && this.pages[ this.currentPageName ] ) {
+ this.pages[ this.currentPageName ].setActive( false );
// Blur anything focused if the next page doesn't have anything focusable - this
// is not needed if the next page has something focusable because once it is focused
// this blur happens automatically
if ( this.autoFocus && !page.$element.find( ':input' ).length ) {
- $focused = this.pages[this.currentPageName].$element.find( ':focus' );
+ $focused = this.pages[ this.currentPageName ].$element.find( ':focus' );
if ( $focused.length ) {
- $focused[0].blur();
+ $focused[ 0 ].blur();
}
}
}
@@ -6436,421 +9286,484 @@ OO.ui.BookletLayout.prototype.setPage = function ( name ) {
};
/**
- * Call this after adding or removing items from the OutlineWidget.
+ * Select the first selectable page.
*
* @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() );
+OO.ui.BookletLayout.prototype.selectFirstSelectablePage = function () {
+ if ( !this.outlineSelectWidget.getSelectedItem() ) {
+ this.outlineSelectWidget.selectItem( this.outlineSelectWidget.getFirstSelectableItem() );
}
return this;
};
/**
- * Layout made of a field and optional label.
+ * IndexLayouts contain {@link OO.ui.CardLayout card layouts} as well as
+ * {@link OO.ui.TabSelectWidget tabs} that allow users to easily navigate through the cards and
+ * select which one to display. By default, only one card is displayed at a time. When a user
+ * navigates to a new card, the index layout automatically focuses on the first focusable element,
+ * unless the default setting is changed.
*
- * @class
- * @extends OO.ui.Layout
- * @mixins OO.ui.LabelElement
+ * TODO: This class is similar to BookletLayout, we may want to refactor to reduce duplication
+ *
+ * @example
+ * // Example of a IndexLayout that contains two CardLayouts.
+ *
+ * function CardOneLayout( name, config ) {
+ * CardOneLayout.super.call( this, name, config );
+ * this.$element.append( '<p>First card</p>' );
+ * }
+ * OO.inheritClass( CardOneLayout, OO.ui.CardLayout );
+ * CardOneLayout.prototype.setupTabItem = function () {
+ * this.tabItem.setLabel( 'Card One' );
+ * };
+ *
+ * function CardTwoLayout( name, config ) {
+ * CardTwoLayout.super.call( this, name, config );
+ * this.$element.append( '<p>Second card</p>' );
+ * }
+ * OO.inheritClass( CardTwoLayout, OO.ui.CardLayout );
+ * CardTwoLayout.prototype.setupTabItem = function () {
+ * this.tabItem.setLabel( 'Card Two' );
+ * };
+ *
+ * var card1 = new CardOneLayout( 'one' ),
+ * card2 = new CardTwoLayout( 'two' );
+ *
+ * var index = new OO.ui.IndexLayout();
*
- * Available label alignment modes include:
- * - left: Label is before the field and aligned away from it, best for when the user will be
- * scanning for a specific label in a form with many fields
- * - right: Label is before the field and aligned toward it, best for forms the user is very
- * familiar with and will tab through field checking quickly to verify which field they are in
- * - top: Label is before the field and above it, best for when the use will need to fill out all
- * fields from top to bottom in a form with few fields
- * - inline: Label is after the field and aligned toward it, best for small boolean fields like
- * checkboxes or radio buttons
+ * index.addCards ( [ card1, card2 ] );
+ * $( 'body' ).append( index.$element );
+ *
+ * @class
+ * @extends OO.ui.MenuLayout
*
* @constructor
- * @param {OO.ui.Widget} field Field widget
* @param {Object} [config] Configuration options
- * @cfg {string} [align='left'] Alignment mode, either 'left', 'right', 'top' or 'inline'
- * @cfg {string} [help] Explanatory text shown as a '?' icon.
+ * @cfg {boolean} [continuous=false] Show all cards, one after another
+ * @cfg {boolean} [autoFocus=true] Focus on the first focusable element when a new card is displayed.
*/
-OO.ui.FieldLayout = function OoUiFieldLayout( field, config ) {
- // Config initialization
- config = $.extend( { align: 'left' }, config );
+OO.ui.IndexLayout = function OoUiIndexLayout( config ) {
+ // Configuration initialization
+ config = $.extend( {}, config, { menuPosition: 'top' } );
// Parent constructor
- OO.ui.FieldLayout.super.call( this, config );
-
- // Mixin constructors
- OO.ui.LabelElement.call( this, config );
+ OO.ui.IndexLayout.super.call( this, config );
// Properties
- this.$field = this.$( '<div>' );
- this.field = field;
- this.align = null;
- if ( config.help ) {
- this.popupButtonWidget = new OO.ui.PopupButtonWidget( {
- $: this.$,
- classes: [ 'oo-ui-fieldLayout-help' ],
- framed: false,
- icon: 'info'
- } );
+ this.currentCardName = null;
+ this.cards = {};
+ this.ignoreFocus = false;
+ this.stackLayout = new OO.ui.StackLayout( { continuous: !!config.continuous } );
+ this.$content.append( this.stackLayout.$element );
+ this.autoFocus = config.autoFocus === undefined || !!config.autoFocus;
- this.popupButtonWidget.getPopup().$body.append(
- this.$( '<div>' )
- .text( config.help )
- .addClass( 'oo-ui-fieldLayout-help-content' )
- );
- this.$help = this.popupButtonWidget.$element;
- } else {
- this.$help = this.$( [] );
- }
+ this.tabSelectWidget = new OO.ui.TabSelectWidget();
+ this.tabPanel = new OO.ui.PanelLayout();
+ this.$menu.append( this.tabPanel.$element );
+
+ this.toggleMenu( true );
// Events
- if ( this.field instanceof OO.ui.InputWidget ) {
- this.$label.on( 'click', OO.ui.bind( this.onLabelClick, this ) );
+ this.stackLayout.connect( this, { set: 'onStackLayoutSet' } );
+ this.tabSelectWidget.connect( this, { select: 'onTabSelectWidgetSelect' } );
+ if ( this.autoFocus ) {
+ // Event 'focus' does not bubble, but 'focusin' does
+ this.stackLayout.$element.on( 'focusin', this.onStackLayoutFocus.bind( this ) );
}
- this.field.connect( this, { disable: 'onFieldDisable' } );
// Initialization
- this.$element.addClass( 'oo-ui-fieldLayout' );
- this.$field
- .addClass( 'oo-ui-fieldLayout-field' )
- .toggleClass( 'oo-ui-fieldLayout-disable', this.field.isDisabled() )
- .append( this.field.$element );
- this.setAlignment( config.align );
+ this.$element.addClass( 'oo-ui-indexLayout' );
+ this.stackLayout.$element.addClass( 'oo-ui-indexLayout-stackLayout' );
+ this.tabPanel.$element
+ .addClass( 'oo-ui-indexLayout-tabPanel' )
+ .append( this.tabSelectWidget.$element );
};
/* Setup */
-OO.inheritClass( OO.ui.FieldLayout, OO.ui.Layout );
-OO.mixinClass( OO.ui.FieldLayout, OO.ui.LabelElement );
+OO.inheritClass( OO.ui.IndexLayout, OO.ui.MenuLayout );
-/* Methods */
+/* Events */
/**
- * Handle field disable events.
- *
- * @param {boolean} value Field is disabled
+ * A 'set' event is emitted when a card is {@link #setCard set} to be displayed by the index layout.
+ * @event set
+ * @param {OO.ui.CardLayout} card Current card
*/
-OO.ui.FieldLayout.prototype.onFieldDisable = function ( value ) {
- this.$element.toggleClass( 'oo-ui-fieldLayout-disabled', value );
-};
/**
- * Handle label mouse click events.
+ * An 'add' event is emitted when cards are {@link #addCards added} to the index layout.
*
- * @param {jQuery.Event} e Mouse click event
+ * @event add
+ * @param {OO.ui.CardLayout[]} card Added cards
+ * @param {number} index Index cards were added at
*/
-OO.ui.FieldLayout.prototype.onLabelClick = function () {
- this.field.simulateLabelClick();
- return false;
-};
/**
- * Get the field.
+ * A 'remove' event is emitted when cards are {@link #clearCards cleared} or
+ * {@link #removeCards removed} from the index.
*
- * @return {OO.ui.Widget} Field widget
+ * @event remove
+ * @param {OO.ui.CardLayout[]} cards Removed cards
*/
-OO.ui.FieldLayout.prototype.getField = function () {
- return this.field;
-};
+
+/* Methods */
/**
- * Set the field alignment mode.
+ * Handle stack layout focus.
*
- * @param {string} value Alignment mode, either 'left', 'right', 'top' or 'inline'
- * @chainable
+ * @private
+ * @param {jQuery.Event} e Focusin event
*/
-OO.ui.FieldLayout.prototype.setAlignment = function ( value ) {
- if ( value !== this.align ) {
- // Default to 'left'
- if ( [ 'left', 'right', 'top', 'inline' ].indexOf( value ) === -1 ) {
- value = 'left';
- }
- // Reorder elements
- if ( value === 'inline' ) {
- this.$element.append( this.$field, this.$label, this.$help );
- } else {
- this.$element.append( this.$help, this.$label, this.$field );
- }
- // Set classes
- if ( this.align ) {
- this.$element.removeClass( 'oo-ui-fieldLayout-align-' + this.align );
+OO.ui.IndexLayout.prototype.onStackLayoutFocus = function ( e ) {
+ var name, $target;
+
+ // Find the card that an element was focused within
+ $target = $( e.target ).closest( '.oo-ui-cardLayout' );
+ for ( name in this.cards ) {
+ // Check for card match, exclude current card to find only card changes
+ if ( this.cards[ name ].$element[ 0 ] === $target[ 0 ] && name !== this.currentCardName ) {
+ this.setCard( name );
+ break;
}
- this.align = value;
- // The following classes can be used here:
- // oo-ui-fieldLayout-align-left
- // oo-ui-fieldLayout-align-right
- // oo-ui-fieldLayout-align-top
- // oo-ui-fieldLayout-align-inline
- this.$element.addClass( 'oo-ui-fieldLayout-align-' + this.align );
}
-
- return this;
};
/**
- * Layout made of a fieldset and optional legend.
- *
- * Just add OO.ui.FieldLayout items.
- *
- * @class
- * @extends OO.ui.Layout
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.GroupElement
+ * Handle stack layout set events.
*
- * @constructor
- * @param {Object} [config] Configuration options
- * @cfg {string} [icon] Symbolic icon name
- * @cfg {OO.ui.FieldLayout[]} [items] Items to add
+ * @private
+ * @param {OO.ui.PanelLayout|null} card The card panel that is now the current panel
*/
-OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
- // Config initialization
- config = config || {};
+OO.ui.IndexLayout.prototype.onStackLayoutSet = function ( card ) {
+ var layout = this;
+ if ( card ) {
+ card.scrollElementIntoView( { complete: function () {
+ if ( layout.autoFocus ) {
+ layout.focus();
+ }
+ } } );
+ }
+};
- // Parent constructor
- OO.ui.FieldsetLayout.super.call( this, config );
+/**
+ * Focus the first input in the current card.
+ *
+ * If no card is selected, the first selectable card will be selected.
+ * If the focus is already in an element on the current card, nothing will happen.
+ * @param {number} [itemIndex] A specific item to focus on
+ */
+OO.ui.IndexLayout.prototype.focus = function ( itemIndex ) {
+ var $input, card,
+ items = this.stackLayout.getItems();
- // Mixin constructors
- OO.ui.IconElement.call( this, config );
- OO.ui.LabelElement.call( this, config );
- OO.ui.GroupElement.call( this, config );
+ if ( itemIndex !== undefined && items[ itemIndex ] ) {
+ card = items[ itemIndex ];
+ } else {
+ card = this.stackLayout.getCurrentItem();
+ }
- // Initialization
- this.$element
- .addClass( 'oo-ui-fieldsetLayout' )
- .prepend( this.$icon, this.$label, this.$group );
- if ( $.isArray( config.items ) ) {
- this.addItems( config.items );
+ if ( !card ) {
+ this.selectFirstSelectableCard();
+ card = this.stackLayout.getCurrentItem();
+ }
+ if ( !card ) {
+ return;
+ }
+ // Only change the focus if is not already in the current card
+ if ( !card.$element.find( ':focus' ).length ) {
+ $input = card.$element.find( ':input:first' );
+ if ( $input.length ) {
+ $input[ 0 ].focus();
+ }
}
};
-/* Setup */
-
-OO.inheritClass( OO.ui.FieldsetLayout, OO.ui.Layout );
-OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.IconElement );
-OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.GroupElement );
-
-/* Static Properties */
+/**
+ * Find the first focusable input in the index layout and focus
+ * on it.
+ */
+OO.ui.IndexLayout.prototype.focusFirstFocusable = function () {
+ var i, len,
+ found = false,
+ items = this.stackLayout.getItems(),
+ checkAndFocus = function () {
+ if ( OO.ui.isFocusableElement( $( this ) ) ) {
+ $( this ).focus();
+ found = true;
+ return false;
+ }
+ };
-OO.ui.FieldsetLayout.static.tagName = 'div';
+ for ( i = 0, len = items.length; i < len; i++ ) {
+ if ( found ) {
+ break;
+ }
+ // Find all potentially focusable elements in the item
+ // and check if they are focusable
+ items[i].$element
+ .find( 'input, select, textarea, button, object' )
+ .each( checkAndFocus );
+ }
+};
/**
- * Layout with an HTML form.
- *
- * @class
- * @extends OO.ui.Layout
+ * Handle tab widget select events.
*
- * @constructor
- * @param {Object} [config] Configuration options
+ * @private
+ * @param {OO.ui.OptionWidget|null} item Selected item
*/
-OO.ui.FormLayout = function OoUiFormLayout( config ) {
- // Configuration initialization
- config = config || {};
-
- // Parent constructor
- OO.ui.FormLayout.super.call( this, config );
-
- // Events
- this.$element.on( 'submit', OO.ui.bind( this.onFormSubmit, this ) );
-
- // Initialization
- this.$element.addClass( 'oo-ui-formLayout' );
+OO.ui.IndexLayout.prototype.onTabSelectWidgetSelect = function ( item ) {
+ if ( item ) {
+ this.setCard( item.getData() );
+ }
};
-/* Setup */
-
-OO.inheritClass( OO.ui.FormLayout, OO.ui.Layout );
+/**
+ * Get the card closest to the specified card.
+ *
+ * @param {OO.ui.CardLayout} card Card to use as a reference point
+ * @return {OO.ui.CardLayout|null} Card closest to the specified card
+ */
+OO.ui.IndexLayout.prototype.getClosestCard = function ( card ) {
+ var next, prev, level,
+ cards = this.stackLayout.getItems(),
+ index = $.inArray( card, cards );
-/* Events */
+ if ( index !== -1 ) {
+ next = cards[ index + 1 ];
+ prev = cards[ index - 1 ];
+ // Prefer adjacent cards at the same level
+ level = this.tabSelectWidget.getItemFromData( card.getName() ).getLevel();
+ if (
+ prev &&
+ level === this.tabSelectWidget.getItemFromData( prev.getName() ).getLevel()
+ ) {
+ return prev;
+ }
+ if (
+ next &&
+ level === this.tabSelectWidget.getItemFromData( next.getName() ).getLevel()
+ ) {
+ return next;
+ }
+ }
+ return prev || next || null;
+};
/**
- * @event submit
+ * Get the tabs widget.
+ *
+ * @return {OO.ui.TabSelectWidget} Tabs widget
*/
+OO.ui.IndexLayout.prototype.getTabs = function () {
+ return this.tabSelectWidget;
+};
-/* Static Properties */
-
-OO.ui.FormLayout.static.tagName = 'form';
+/**
+ * Get a card by its symbolic name.
+ *
+ * @param {string} name Symbolic name of card
+ * @return {OO.ui.CardLayout|undefined} Card, if found
+ */
+OO.ui.IndexLayout.prototype.getCard = function ( name ) {
+ return this.cards[ name ];
+};
-/* Methods */
+/**
+ * Get the current card.
+ *
+ * @return {OO.ui.CardLayout|undefined} Current card, if found
+ */
+OO.ui.IndexLayout.prototype.getCurrentCard = function () {
+ var name = this.getCurrentCardName();
+ return name ? this.getCard( name ) : undefined;
+};
/**
- * Handle form submit events.
+ * Get the symbolic name of the current card.
*
- * @param {jQuery.Event} e Submit event
- * @fires submit
+ * @return {string|null} Symbolic name of the current card
*/
-OO.ui.FormLayout.prototype.onFormSubmit = function () {
- this.emit( 'submit' );
- return false;
+OO.ui.IndexLayout.prototype.getCurrentCardName = function () {
+ return this.currentCardName;
};
/**
- * Layout made of proportionally sized columns and rows.
+ * Add cards to the index layout
*
- * @class
- * @extends OO.ui.Layout
+ * When cards are added with the same names as existing cards, the existing cards will be
+ * automatically removed before the new cards are added.
*
- * @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
+ * @param {OO.ui.CardLayout[]} cards Cards to add
+ * @param {number} index Index of the insertion point
+ * @fires add
+ * @chainable
*/
-OO.ui.GridLayout = function OoUiGridLayout( panels, config ) {
- var i, len, widths;
-
- // Config initialization
- config = config || {};
+OO.ui.IndexLayout.prototype.addCards = function ( cards, index ) {
+ var i, len, name, card, item, currentIndex,
+ stackLayoutCards = this.stackLayout.getItems(),
+ remove = [],
+ items = [];
- // Parent constructor
- OO.ui.GridLayout.super.call( this, config );
+ // Remove cards with same names
+ for ( i = 0, len = cards.length; i < len; i++ ) {
+ card = cards[ i ];
+ name = card.getName();
- // 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;
+ if ( Object.prototype.hasOwnProperty.call( this.cards, name ) ) {
+ // Correct the insertion index
+ currentIndex = $.inArray( this.cards[ name ], stackLayoutCards );
+ if ( currentIndex !== -1 && currentIndex + 1 < index ) {
+ index--;
+ }
+ remove.push( this.cards[ name ] );
}
- this.layout( widths, [ 1 ] );
}
-};
-
-/* Setup */
+ if ( remove.length ) {
+ this.removeCards( remove );
+ }
-OO.inheritClass( OO.ui.GridLayout, OO.ui.Layout );
+ // Add new cards
+ for ( i = 0, len = cards.length; i < len; i++ ) {
+ card = cards[ i ];
+ name = card.getName();
+ this.cards[ card.getName() ] = card;
+ item = new OO.ui.TabOptionWidget( { data: name } );
+ card.setTabItem( item );
+ items.push( item );
+ }
-/* Events */
+ if ( items.length ) {
+ this.tabSelectWidget.addItems( items, index );
+ this.selectFirstSelectableCard();
+ }
+ this.stackLayout.addItems( cards, index );
+ this.emit( 'add', cards, index );
-/**
- * @event layout
- */
+ return this;
+};
/**
- * @event update
+ * Remove the specified cards from the index layout.
+ *
+ * To remove all cards from the index, you may wish to use the #clearCards method instead.
+ *
+ * @param {OO.ui.CardLayout[]} cards An array of cards to remove
+ * @fires remove
+ * @chainable
*/
+OO.ui.IndexLayout.prototype.removeCards = function ( cards ) {
+ var i, len, name, card,
+ items = [];
-/* Static Properties */
-
-OO.ui.GridLayout.static.tagName = 'div';
+ for ( i = 0, len = cards.length; i < len; i++ ) {
+ card = cards[ i ];
+ name = card.getName();
+ delete this.cards[ name ];
+ items.push( this.tabSelectWidget.getItemFromData( name ) );
+ card.setTabItem( null );
+ }
+ if ( items.length ) {
+ this.tabSelectWidget.removeItems( items );
+ this.selectFirstSelectableCard();
+ }
+ this.stackLayout.removeItems( cards );
+ this.emit( 'remove', cards );
-/* Methods */
+ return this;
+};
/**
- * Set grid dimensions.
+ * Clear all cards from the index layout.
+ *
+ * To remove only a subset of cards from the index, use the #removeCards 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
+ * @fires remove
+ * @chainable
*/
-OO.ui.GridLayout.prototype.layout = function ( widths, heights ) {
- var x, y,
- xd = 0,
- yd = 0,
- cols = widths.length,
- rows = heights.length;
+OO.ui.IndexLayout.prototype.clearCards = function () {
+ var i, len,
+ cards = this.stackLayout.getItems();
- // 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' );
+ this.cards = {};
+ this.currentCardName = null;
+ this.tabSelectWidget.clearItems();
+ for ( i = 0, len = cards.length; i < len; i++ ) {
+ cards[ i ].setTabItem( null );
}
+ this.stackLayout.clearItems();
- // 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' );
+ this.emit( 'remove', cards );
+
+ return this;
};
/**
- * Update panel positions and sizes.
+ * Set the current card by symbolic name.
*
- * @fires update
+ * @fires set
+ * @param {string} name Symbolic name of card
*/
-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;
+OO.ui.IndexLayout.prototype.setCard = function ( name ) {
+ var selectedItem,
+ $focused,
+ card = this.cards[ name ];
- for ( y = 0; y < rows; y++ ) {
- height = this.heights[y];
- for ( x = 0; x < cols; x++ ) {
- panel = this.panels[i];
- width = this.widths[x];
- dimensions = {
- width: Math.round( width * 100 ) + '%',
- height: Math.round( height * 100 ) + '%',
- top: Math.round( top * 100 ) + '%',
- // HACK: Work around IE bug by setting visibility: hidden; if width or height is zero
- visibility: width === 0 || height === 0 ? 'hidden' : ''
- };
- // If RTL, reverse:
- if ( OO.ui.Element.getDir( this.$.context ) === 'rtl' ) {
- dimensions.right = Math.round( left * 100 ) + '%';
- } else {
- dimensions.left = Math.round( left * 100 ) + '%';
+ if ( name !== this.currentCardName ) {
+ selectedItem = this.tabSelectWidget.getSelectedItem();
+ if ( selectedItem && selectedItem.getData() !== name ) {
+ this.tabSelectWidget.selectItemByData( name );
+ }
+ if ( card ) {
+ if ( this.currentCardName && this.cards[ this.currentCardName ] ) {
+ this.cards[ this.currentCardName ].setActive( false );
+ // Blur anything focused if the next card doesn't have anything focusable - this
+ // is not needed if the next card has something focusable because once it is focused
+ // this blur happens automatically
+ if ( this.autoFocus && !card.$element.find( ':input' ).length ) {
+ $focused = this.cards[ this.currentCardName ].$element.find( ':focus' );
+ if ( $focused.length ) {
+ $focused[ 0 ].blur();
+ }
+ }
}
- panel.$element.css( dimensions );
- i++;
- left += width;
+ this.currentCardName = name;
+ this.stackLayout.setItem( card );
+ card.setActive( true );
+ this.emit( 'set', card );
}
- top += height;
- left = 0;
}
-
- this.emit( 'update' );
};
/**
- * Get a panel at a given position.
+ * Select the first selectable card.
*
- * The x and y position is affected by the current grid layout.
- *
- * @param {number} x Horizontal position
- * @param {number} y Vertical position
- * @return {OO.ui.PanelLayout} The panel at the given postion
+ * @chainable
*/
-OO.ui.GridLayout.prototype.getPanel = function ( x, y ) {
- return this.panels[( x * this.widths.length ) + y];
+OO.ui.IndexLayout.prototype.selectFirstSelectableCard = function () {
+ if ( !this.tabSelectWidget.getSelectedItem() ) {
+ this.tabSelectWidget.selectItem( this.tabSelectWidget.getFirstSelectableItem() );
+ }
+
+ return this;
};
/**
- * Layout that expands to cover the entire area of its parent, with optional scrolling and padding.
+ * PanelLayouts expand to cover the entire area of their parent. They can be configured with scrolling, padding,
+ * and a frame, and are often used together with {@link OO.ui.StackLayout StackLayouts}.
+ *
+ * @example
+ * // Example of a panel layout
+ * var panel = new OO.ui.PanelLayout( {
+ * expanded: false,
+ * framed: true,
+ * padded: true,
+ * $content: $( '<p>A panel layout with padding and a frame.</p>' )
+ * } );
+ * $( 'body' ).append( panel.$element );
*
* @class
* @extends OO.ui.Layout
@@ -6858,12 +9771,18 @@ OO.ui.GridLayout.prototype.getPanel = function ( x, y ) {
* @constructor
* @param {Object} [config] Configuration options
* @cfg {boolean} [scrollable=false] Allow vertical scrolling
- * @cfg {boolean} [padded=false] Pad the content from the edges
- * @cfg {boolean} [expanded=true] Expand size to fill the entire parent element
+ * @cfg {boolean} [padded=false] Add padding between the content and the edges of the panel.
+ * @cfg {boolean} [expanded=true] Expand the panel to fill the entire parent element.
+ * @cfg {boolean} [framed=false] Render the panel with a frame to visually separate it from outside content.
*/
OO.ui.PanelLayout = function OoUiPanelLayout( config ) {
- // Config initialization
- config = config || {};
+ // Configuration initialization
+ config = $.extend( {
+ scrollable: false,
+ padded: false,
+ expanded: true,
+ framed: false
+ }, config );
// Parent constructor
OO.ui.PanelLayout.super.call( this, config );
@@ -6873,14 +9792,15 @@ OO.ui.PanelLayout = function OoUiPanelLayout( config ) {
if ( config.scrollable ) {
this.$element.addClass( 'oo-ui-panelLayout-scrollable' );
}
-
if ( config.padded ) {
this.$element.addClass( 'oo-ui-panelLayout-padded' );
}
-
- if ( config.expanded === undefined || config.expanded ) {
+ if ( config.expanded ) {
this.$element.addClass( 'oo-ui-panelLayout-expanded' );
}
+ if ( config.framed ) {
+ this.$element.addClass( 'oo-ui-panelLayout-framed' );
+ }
};
/* Setup */
@@ -6888,7 +9808,152 @@ OO.ui.PanelLayout = function OoUiPanelLayout( config ) {
OO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout );
/**
- * Page within an booklet layout.
+ * CardLayouts are used within {@link OO.ui.IndexLayout index layouts} to create cards that users can select and display
+ * from the index's optional {@link OO.ui.TabSelectWidget tab} navigation. Cards are usually not instantiated directly,
+ * rather extended to include the required content and functionality.
+ *
+ * Each card must have a unique symbolic name, which is passed to the constructor. In addition, the card's tab
+ * item is customized (with a label) using the #setupTabItem method. See
+ * {@link OO.ui.IndexLayout IndexLayout} for an example.
+ *
+ * @class
+ * @extends OO.ui.PanelLayout
+ *
+ * @constructor
+ * @param {string} name Unique symbolic name of card
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.CardLayout = function OoUiCardLayout( name, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( name ) && config === undefined ) {
+ config = name;
+ name = config.name;
+ }
+
+ // Configuration initialization
+ config = $.extend( { scrollable: true }, config );
+
+ // Parent constructor
+ OO.ui.CardLayout.super.call( this, config );
+
+ // Properties
+ this.name = name;
+ this.tabItem = null;
+ this.active = false;
+
+ // Initialization
+ this.$element.addClass( 'oo-ui-cardLayout' );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.CardLayout, OO.ui.PanelLayout );
+
+/* Events */
+
+/**
+ * An 'active' event is emitted when the card becomes active. Cards become active when they are
+ * shown in a index layout that is configured to display only one card at a time.
+ *
+ * @event active
+ * @param {boolean} active Card is active
+ */
+
+/* Methods */
+
+/**
+ * Get the symbolic name of the card.
+ *
+ * @return {string} Symbolic name of card
+ */
+OO.ui.CardLayout.prototype.getName = function () {
+ return this.name;
+};
+
+/**
+ * Check if card is active.
+ *
+ * Cards become active when they are shown in a {@link OO.ui.IndexLayout index layout} that is configured to display
+ * only one card at a time. Additional CSS is applied to the card's tab item to reflect the active state.
+ *
+ * @return {boolean} Card is active
+ */
+OO.ui.CardLayout.prototype.isActive = function () {
+ return this.active;
+};
+
+/**
+ * Get tab item.
+ *
+ * The tab item allows users to access the card from the index's tab
+ * navigation. The tab item itself can be customized (with a label, level, etc.) using the #setupTabItem method.
+ *
+ * @return {OO.ui.TabOptionWidget|null} Tab option widget
+ */
+OO.ui.CardLayout.prototype.getTabItem = function () {
+ return this.tabItem;
+};
+
+/**
+ * Set or unset the tab item.
+ *
+ * Specify a {@link OO.ui.TabOptionWidget tab option} to set it,
+ * or `null` to clear the tab item. To customize the tab item itself (e.g., to set a label or tab
+ * level), use #setupTabItem instead of this method.
+ *
+ * @param {OO.ui.TabOptionWidget|null} tabItem Tab option widget, null to clear
+ * @chainable
+ */
+OO.ui.CardLayout.prototype.setTabItem = function ( tabItem ) {
+ this.tabItem = tabItem || null;
+ if ( tabItem ) {
+ this.setupTabItem();
+ }
+ return this;
+};
+
+/**
+ * Set up the tab item.
+ *
+ * Use this method to customize the tab item (e.g., to add a label or tab level). To set or unset
+ * the tab item itself (with a {@link OO.ui.TabOptionWidget tab option} or `null`), use
+ * the #setTabItem method instead.
+ *
+ * @param {OO.ui.TabOptionWidget} tabItem Tab option widget to set up
+ * @chainable
+ */
+OO.ui.CardLayout.prototype.setupTabItem = function () {
+ return this;
+};
+
+/**
+ * Set the card to its 'active' state.
+ *
+ * Cards become active when they are shown in a index layout that is configured to display only one card at a time. Additional
+ * CSS is applied to the tab item to reflect the card's active state. Outside of the index
+ * context, setting the active state on a card does nothing.
+ *
+ * @param {boolean} value Card is active
+ * @fires active
+ */
+OO.ui.CardLayout.prototype.setActive = function ( active ) {
+ active = !!active;
+
+ if ( active !== this.active ) {
+ this.active = active;
+ this.$element.toggleClass( 'oo-ui-cardLayout-active', this.active );
+ this.emit( 'active', this.active );
+ }
+};
+
+/**
+ * PageLayouts are used within {@link OO.ui.BookletLayout booklet layouts} to create pages that users can select and display
+ * from the booklet's optional {@link OO.ui.OutlineSelectWidget outline} navigation. Pages are usually not instantiated directly,
+ * rather extended to include the required content and functionality.
+ *
+ * Each page must have a unique symbolic name, which is passed to the constructor. In addition, the page's outline
+ * item is customized (with a label, outline level, etc.) using the #setupOutlineItem method. See
+ * {@link OO.ui.BookletLayout BookletLayout} for an example.
*
* @class
* @extends OO.ui.PanelLayout
@@ -6896,9 +9961,14 @@ OO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout );
* @constructor
* @param {string} name Unique symbolic name of page
* @param {Object} [config] Configuration options
- * @param {string} [outlineItem] Outline item widget
*/
OO.ui.PageLayout = function OoUiPageLayout( name, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( name ) && config === undefined ) {
+ config = name;
+ name = config.name;
+ }
+
// Configuration initialization
config = $.extend( { scrollable: true }, config );
@@ -6907,7 +9977,7 @@ OO.ui.PageLayout = function OoUiPageLayout( name, config ) {
// Properties
this.name = name;
- this.outlineItem = config.outlineItem || null;
+ this.outlineItem = null;
this.active = false;
// Initialization
@@ -6921,6 +9991,9 @@ OO.inheritClass( OO.ui.PageLayout, OO.ui.PanelLayout );
/* Events */
/**
+ * An 'active' event is emitted when the page becomes active. Pages become active when they are
+ * shown in a booklet layout that is configured to display only one page at a time.
+ *
* @event active
* @param {boolean} active Page is active
*/
@@ -6928,7 +10001,7 @@ OO.inheritClass( OO.ui.PageLayout, OO.ui.PanelLayout );
/* Methods */
/**
- * Get page name.
+ * Get the symbolic name of the page.
*
* @return {string} Symbolic name of page
*/
@@ -6939,6 +10012,9 @@ OO.ui.PageLayout.prototype.getName = function () {
/**
* Check if page is active.
*
+ * Pages become active when they are shown in a {@link OO.ui.BookletLayout booklet layout} that is configured to display
+ * only one page at a time. Additional CSS is applied to the page's outline item to reflect the active state.
+ *
* @return {boolean} Page is active
*/
OO.ui.PageLayout.prototype.isActive = function () {
@@ -6948,21 +10024,23 @@ OO.ui.PageLayout.prototype.isActive = function () {
/**
* Get outline item.
*
- * @return {OO.ui.OutlineItemWidget|null} Outline item widget
+ * The outline item allows users to access the page from the booklet's outline
+ * navigation. The outline item itself can be customized (with a label, level, etc.) using the #setupOutlineItem method.
+ *
+ * @return {OO.ui.OutlineOptionWidget|null} Outline option widget
*/
OO.ui.PageLayout.prototype.getOutlineItem = function () {
return this.outlineItem;
};
/**
- * Set outline item.
+ * Set or unset the outline item.
*
- * @localdoc Subclasses should override #setupOutlineItem instead of this method to adjust the
- * outline item as desired; this method is called for setting (with an object) and unsetting
- * (with null) and overriding methods would have to check the value of `outlineItem` to avoid
- * operating on null instead of an OO.ui.OutlineItemWidget object.
+ * Specify an {@link OO.ui.OutlineOptionWidget outline option} to set it,
+ * or `null` to clear the outline item. To customize the outline item itself (e.g., to set a label or outline
+ * level), use #setupOutlineItem instead of this method.
*
- * @param {OO.ui.OutlineItemWidget|null} outlineItem Outline item widget, null to clear
+ * @param {OO.ui.OutlineOptionWidget|null} outlineItem Outline option widget, null to clear
* @chainable
*/
OO.ui.PageLayout.prototype.setOutlineItem = function ( outlineItem ) {
@@ -6974,11 +10052,13 @@ OO.ui.PageLayout.prototype.setOutlineItem = function ( outlineItem ) {
};
/**
- * Setup outline item.
+ * Set up the outline item.
*
- * @localdoc Subclasses should override this method to adjust the outline item as desired.
+ * Use this method to customize the outline item (e.g., to add a label or outline level). To set or unset
+ * the outline item itself (with an {@link OO.ui.OutlineOptionWidget outline option} or `null`), use
+ * the #setOutlineItem method instead.
*
- * @param {OO.ui.OutlineItemWidget} outlineItem Outline item widget to setup
+ * @param {OO.ui.OutlineOptionWidget} outlineItem Outline option widget to set up
* @chainable
*/
OO.ui.PageLayout.prototype.setupOutlineItem = function () {
@@ -6986,9 +10066,13 @@ OO.ui.PageLayout.prototype.setupOutlineItem = function () {
};
/**
- * Set page active state.
+ * Set the page to its 'active' state.
+ *
+ * Pages become active when they are shown in a booklet layout that is configured to display only one page at a time. Additional
+ * CSS is applied to the outline item to reflect the page's active state. Outside of the booklet
+ * context, setting the active state on a page does nothing.
*
- * @param {boolean} Page is active
+ * @param {boolean} value Page is active
* @fires active
*/
OO.ui.PageLayout.prototype.setActive = function ( active ) {
@@ -7002,7 +10086,28 @@ OO.ui.PageLayout.prototype.setActive = function ( active ) {
};
/**
- * Layout containing a series of mutually exclusive pages.
+ * StackLayouts contain a series of {@link OO.ui.PanelLayout panel layouts}. By default, only one panel is displayed
+ * at a time, though the stack layout can also be configured to show all contained panels, one after another,
+ * by setting the #continuous option to 'true'.
+ *
+ * @example
+ * // A stack layout with two panels, configured to be displayed continously
+ * var myStack = new OO.ui.StackLayout( {
+ * items: [
+ * new OO.ui.PanelLayout( {
+ * $content: $( '<p>Panel One</p>' ),
+ * padded: true,
+ * framed: true
+ * } ),
+ * new OO.ui.PanelLayout( {
+ * $content: $( '<p>Panel Two</p>' ),
+ * padded: true,
+ * framed: true
+ * } )
+ * ],
+ * continuous: true
+ * } );
+ * $( 'body' ).append( myStack.$element );
*
* @class
* @extends OO.ui.PanelLayout
@@ -7010,12 +10115,11 @@ OO.ui.PageLayout.prototype.setActive = function ( active ) {
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {boolean} [continuous=false] Show all pages, one after another
- * @cfg {string} [icon=''] Symbolic icon name
- * @cfg {OO.ui.Layout[]} [items] Layouts to add
+ * @cfg {boolean} [continuous=false] Show all panels, one after another. By default, only one panel is displayed at a time.
+ * @cfg {OO.ui.Layout[]} [items] Panel layouts to add to the stack layout.
*/
OO.ui.StackLayout = function OoUiStackLayout( config ) {
- // Config initialization
+ // Configuration initialization
config = $.extend( { scrollable: true }, config );
// Parent constructor
@@ -7033,7 +10137,7 @@ OO.ui.StackLayout = function OoUiStackLayout( config ) {
if ( this.continuous ) {
this.$element.addClass( 'oo-ui-stackLayout-continuous' );
}
- if ( $.isArray( config.items ) ) {
+ if ( Array.isArray( config.items ) ) {
this.addItems( config.items );
}
};
@@ -7046,14 +10150,17 @@ OO.mixinClass( OO.ui.StackLayout, OO.ui.GroupElement );
/* Events */
/**
+ * A 'set' event is emitted when panels are {@link #addItems added}, {@link #removeItems removed},
+ * {@link #clearItems cleared} or {@link #setItem displayed}.
+ *
* @event set
- * @param {OO.ui.Layout|null} item Current item or null if there is no longer a layout shown
+ * @param {OO.ui.Layout|null} item Current panel or `null` if no panel is shown
*/
/* Methods */
/**
- * Get the current item.
+ * Get the current panel.
*
* @return {OO.ui.Layout|null}
*/
@@ -7079,31 +10186,37 @@ OO.ui.StackLayout.prototype.unsetCurrentItem = function () {
};
/**
- * Add items.
+ * Add panel layouts to the stack layout.
*
- * Adding an existing item (by value) will move it.
+ * Panels will be added to the end of the stack layout array unless the optional index parameter specifies a different
+ * insertion point. Adding a panel that is already in the stack will move it to the end of the array or the point specified
+ * by the index.
*
- * @param {OO.ui.Layout[]} items Items to add
- * @param {number} [index] Index to insert items after
+ * @param {OO.ui.Layout[]} items Panels to add
+ * @param {number} [index] Index of the insertion point
* @chainable
*/
OO.ui.StackLayout.prototype.addItems = function ( items, index ) {
+ // Update the visibility
+ this.updateHiddenState( items, this.currentItem );
+
// Mixin method
OO.ui.GroupElement.prototype.addItems.call( this, items, index );
if ( !this.currentItem && items.length ) {
- this.setItem( items[0] );
+ this.setItem( items[ 0 ] );
}
return this;
};
/**
- * Remove items.
+ * Remove the specified panels from the stack layout.
*
- * Items will be detached, not removed, so they can be used later.
+ * Removed panels are detached from the DOM, not removed, so that they may be reused. To remove all panels,
+ * you may wish to use the #clearItems method instead.
*
- * @param {OO.ui.Layout[]} items Items to remove
+ * @param {OO.ui.Layout[]} items Panels to remove
* @chainable
* @fires set
*/
@@ -7113,7 +10226,7 @@ OO.ui.StackLayout.prototype.removeItems = function ( items ) {
if ( $.inArray( this.currentItem, items ) !== -1 ) {
if ( this.items.length ) {
- this.setItem( this.items[0] );
+ this.setItem( this.items[ 0 ] );
} else {
this.unsetCurrentItem();
}
@@ -7123,9 +10236,10 @@ OO.ui.StackLayout.prototype.removeItems = function ( items ) {
};
/**
- * Clear all items.
+ * Clear all panels from the stack layout.
*
- * Items will be detached, not removed, so they can be used later.
+ * Cleared panels are detached from the DOM, not removed, so that they may be reused. To remove only
+ * a subset of panels, use the #removeItems method.
*
* @chainable
* @fires set
@@ -7138,30 +10252,19 @@ OO.ui.StackLayout.prototype.clearItems = function () {
};
/**
- * Show item.
- *
- * Any currently shown item will be hidden.
+ * Show the specified panel.
*
- * FIXME: If the passed item to show has not been added in the items list, then
- * this method drops it and unsets the current item.
+ * If another panel is currently displayed, it will be hidden.
*
- * @param {OO.ui.Layout} item Item to show
+ * @param {OO.ui.Layout} item Panel to show
* @chainable
* @fires set
*/
OO.ui.StackLayout.prototype.setItem = function ( item ) {
- var i, len;
-
if ( item !== this.currentItem ) {
- if ( !this.continuous ) {
- for ( i = 0, len = this.items.length; i < len; i++ ) {
- this.items[i].$element.css( 'display', '' );
- }
- }
+ this.updateHiddenState( this.items, item );
+
if ( $.inArray( item, this.items ) !== -1 ) {
- if ( !this.continuous ) {
- item.$element.css( 'display', 'block' );
- }
this.currentItem = item;
this.emit( 'set', item );
} else {
@@ -7173,6 +10276,31 @@ OO.ui.StackLayout.prototype.setItem = function ( item ) {
};
/**
+ * Update the visibility of all items in case of non-continuous view.
+ *
+ * Ensure all items are hidden except for the selected one.
+ * This method does nothing when the stack is continuous.
+ *
+ * @private
+ * @param {OO.ui.Layout[]} items Item list iterate over
+ * @param {OO.ui.Layout} [selectedItem] Selected item to show
+ */
+OO.ui.StackLayout.prototype.updateHiddenState = function ( items, selectedItem ) {
+ var i, len;
+
+ if ( !this.continuous ) {
+ for ( i = 0, len = items.length; i < len; i++ ) {
+ if ( !selectedItem || selectedItem !== items[ i ] ) {
+ items[ i ].$element.addClass( 'oo-ui-element-hidden' );
+ }
+ }
+ if ( selectedItem ) {
+ selectedItem.$element.removeClass( 'oo-ui-element-hidden' );
+ }
+ }
+};
+
+/**
* Horizontal bar layout of tools as icon buttons.
*
* @class
@@ -7183,6 +10311,12 @@ OO.ui.StackLayout.prototype.setItem = function ( item ) {
* @param {Object} [config] Configuration options
*/
OO.ui.BarToolGroup = function OoUiBarToolGroup( toolbar, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( toolbar ) && config === undefined ) {
+ config = toolbar;
+ toolbar = config.toolbar;
+ }
+
// Parent constructor
OO.ui.BarToolGroup.super.call( this, toolbar, config );
@@ -7213,6 +10347,7 @@ OO.ui.BarToolGroup.static.name = 'bar';
* @mixins OO.ui.LabelElement
* @mixins OO.ui.TitledElement
* @mixins OO.ui.ClippableElement
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
* @param {OO.ui.Toolbar} toolbar
@@ -7220,29 +10355,38 @@ OO.ui.BarToolGroup.static.name = 'bar';
* @cfg {string} [header] Text to display at the top of the pop-up
*/
OO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( toolbar ) && config === undefined ) {
+ config = toolbar;
+ toolbar = config.toolbar;
+ }
+
// Configuration initialization
config = config || {};
// Parent constructor
OO.ui.PopupToolGroup.super.call( this, toolbar, config );
+ // Properties
+ this.active = false;
+ this.dragging = false;
+ this.onBlurHandler = this.onBlur.bind( this );
+ this.$handle = $( '<span>' );
+
// Mixin constructors
OO.ui.IconElement.call( this, config );
OO.ui.IndicatorElement.call( this, config );
OO.ui.LabelElement.call( this, config );
OO.ui.TitledElement.call( this, config );
OO.ui.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$group } ) );
-
- // Properties
- this.active = false;
- this.dragging = false;
- this.onBlurHandler = OO.ui.bind( this.onBlur, this );
- this.$handle = this.$( '<span>' );
+ OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$handle } ) );
// Events
this.$handle.on( {
- 'mousedown touchstart': OO.ui.bind( this.onHandlePointerDown, this ),
- 'mouseup touchend': OO.ui.bind( this.onHandlePointerUp, this )
+ keydown: this.onHandleMouseKeyDown.bind( this ),
+ keyup: this.onHandleMouseKeyUp.bind( this ),
+ mousedown: this.onHandleMouseKeyDown.bind( this ),
+ mouseup: this.onHandleMouseKeyUp.bind( this )
} );
// Initialization
@@ -7254,7 +10398,7 @@ OO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {
// OO.ui.HeaderedElement mixin constructor.
if ( config.header !== undefined ) {
this.$group
- .prepend( this.$( '<span>' )
+ .prepend( $( '<span>' )
.addClass( 'oo-ui-popupToolGroup-header' )
.text( config.header )
);
@@ -7272,8 +10416,7 @@ OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.IndicatorElement );
OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.LabelElement );
OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.TitledElement );
OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.ClippableElement );
-
-/* Static Properties */
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.TabIndexedElement );
/* Methods */
@@ -7292,13 +10435,13 @@ OO.ui.PopupToolGroup.prototype.setDisabled = function () {
/**
* Handle focus being lost.
*
- * The event is actually generated from a mouseup, so it is not a normal blur event object.
+ * The event is actually generated from a mouseup/keyup, so it is not a normal blur event object.
*
- * @param {jQuery.Event} e Mouse up event
+ * @param {jQuery.Event} e Mouse up or key 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] ) {
+ if ( $( e.target ).closest( '.oo-ui-popupToolGroup' )[ 0 ] !== this.$element[ 0 ] ) {
this.setActive( false );
}
};
@@ -7306,34 +10449,44 @@ OO.ui.PopupToolGroup.prototype.onBlur = function ( e ) {
/**
* @inheritdoc
*/
-OO.ui.PopupToolGroup.prototype.onPointerUp = function ( e ) {
- // e.which is 0 for touch events, 1 for left mouse button
- if ( !this.isDisabled() && e.which <= 1 ) {
+OO.ui.PopupToolGroup.prototype.onMouseKeyUp = function ( e ) {
+ // Only close toolgroup when a tool was actually selected
+ if (
+ !this.isDisabled() && this.pressed && this.pressed === this.getTargetTool( e ) &&
+ ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
+ ) {
this.setActive( false );
}
- return OO.ui.PopupToolGroup.super.prototype.onPointerUp.call( this, e );
+ return OO.ui.PopupToolGroup.super.prototype.onMouseKeyUp.call( this, e );
};
/**
- * Handle mouse up events.
+ * Handle mouse up and key up events.
*
- * @param {jQuery.Event} e Mouse up event
+ * @param {jQuery.Event} e Mouse up or key up event
*/
-OO.ui.PopupToolGroup.prototype.onHandlePointerUp = function () {
- return false;
+OO.ui.PopupToolGroup.prototype.onHandleMouseKeyUp = function ( e ) {
+ if (
+ !this.isDisabled() &&
+ ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
+ ) {
+ return false;
+ }
};
/**
- * Handle mouse down events.
+ * Handle mouse down and key down events.
*
- * @param {jQuery.Event} e Mouse down event
+ * @param {jQuery.Event} e Mouse down or key down event
*/
-OO.ui.PopupToolGroup.prototype.onHandlePointerDown = function ( e ) {
- // e.which is 0 for touch events, 1 for left mouse button
- if ( !this.isDisabled() && e.which <= 1 ) {
+OO.ui.PopupToolGroup.prototype.onHandleMouseKeyDown = function ( e ) {
+ if (
+ !this.isDisabled() &&
+ ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
+ ) {
this.setActive( !this.active );
+ return false;
}
- return false;
};
/**
@@ -7347,6 +10500,7 @@ OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
this.active = value;
if ( value ) {
this.getElementDocument().addEventListener( 'mouseup', this.onBlurHandler, true );
+ this.getElementDocument().addEventListener( 'keyup', this.onBlurHandler, true );
// Try anchoring the popup to the left first
this.$element.addClass( 'oo-ui-popupToolGroup-active oo-ui-popupToolGroup-left' );
@@ -7361,6 +10515,7 @@ OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
}
} else {
this.getElementDocument().removeEventListener( 'mouseup', this.onBlurHandler, true );
+ this.getElementDocument().removeEventListener( 'keyup', this.onBlurHandler, true );
this.$element.removeClass(
'oo-ui-popupToolGroup-active oo-ui-popupToolGroup-left oo-ui-popupToolGroup-right'
);
@@ -7372,14 +10527,38 @@ OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
/**
* Drop down list layout of tools as labeled icon buttons.
*
+ * This layout allows some tools to be collapsible, controlled by a "More" / "Fewer" option at the
+ * bottom of the main list. These are not automatically positioned at the bottom of the list; you
+ * may want to use the 'promote' and 'demote' configuration options to achieve this.
+ *
* @class
* @extends OO.ui.PopupToolGroup
*
* @constructor
* @param {OO.ui.Toolbar} toolbar
* @param {Object} [config] Configuration options
+ * @cfg {Array} [allowCollapse] List of tools that can be collapsed. Remaining tools will be always
+ * shown.
+ * @cfg {Array} [forceExpand] List of tools that *may not* be collapsed. All remaining tools will be
+ * allowed to be collapsed.
+ * @cfg {boolean} [expanded=false] Whether the collapsible tools are expanded by default
*/
OO.ui.ListToolGroup = function OoUiListToolGroup( toolbar, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( toolbar ) && config === undefined ) {
+ config = toolbar;
+ toolbar = config.toolbar;
+ }
+
+ // Configuration initialization
+ config = config || {};
+
+ // Properties (must be set before parent constructor, which calls #populate)
+ this.allowCollapse = config.allowCollapse;
+ this.forceExpand = config.forceExpand;
+ this.expanded = config.expanded !== undefined ? config.expanded : false;
+ this.collapsibleTools = [];
+
// Parent constructor
OO.ui.ListToolGroup.super.call( this, toolbar, config );
@@ -7393,10 +10572,92 @@ OO.inheritClass( OO.ui.ListToolGroup, OO.ui.PopupToolGroup );
/* Static Properties */
-OO.ui.ListToolGroup.static.accelTooltips = true;
-
OO.ui.ListToolGroup.static.name = 'list';
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+OO.ui.ListToolGroup.prototype.populate = function () {
+ var i, len, allowCollapse = [];
+
+ OO.ui.ListToolGroup.super.prototype.populate.call( this );
+
+ // Update the list of collapsible tools
+ if ( this.allowCollapse !== undefined ) {
+ allowCollapse = this.allowCollapse;
+ } else if ( this.forceExpand !== undefined ) {
+ allowCollapse = OO.simpleArrayDifference( Object.keys( this.tools ), this.forceExpand );
+ }
+
+ this.collapsibleTools = [];
+ for ( i = 0, len = allowCollapse.length; i < len; i++ ) {
+ if ( this.tools[ allowCollapse[ i ] ] !== undefined ) {
+ this.collapsibleTools.push( this.tools[ allowCollapse[ i ] ] );
+ }
+ }
+
+ // Keep at the end, even when tools are added
+ this.$group.append( this.getExpandCollapseTool().$element );
+
+ this.getExpandCollapseTool().toggle( this.collapsibleTools.length !== 0 );
+ this.updateCollapsibleState();
+};
+
+OO.ui.ListToolGroup.prototype.getExpandCollapseTool = function () {
+ if ( this.expandCollapseTool === undefined ) {
+ var ExpandCollapseTool = function () {
+ ExpandCollapseTool.super.apply( this, arguments );
+ };
+
+ OO.inheritClass( ExpandCollapseTool, OO.ui.Tool );
+
+ ExpandCollapseTool.prototype.onSelect = function () {
+ this.toolGroup.expanded = !this.toolGroup.expanded;
+ this.toolGroup.updateCollapsibleState();
+ this.setActive( false );
+ };
+ ExpandCollapseTool.prototype.onUpdateState = function () {
+ // Do nothing. Tool interface requires an implementation of this function.
+ };
+
+ ExpandCollapseTool.static.name = 'more-fewer';
+
+ this.expandCollapseTool = new ExpandCollapseTool( this );
+ }
+ return this.expandCollapseTool;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.ListToolGroup.prototype.onMouseKeyUp = function ( e ) {
+ // Do not close the popup when the user wants to show more/fewer tools
+ if (
+ $( e.target ).closest( '.oo-ui-tool-name-more-fewer' ).length &&
+ ( e.which === 1 || e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
+ ) {
+ // HACK: Prevent the popup list from being hidden. Skip the PopupToolGroup implementation (which
+ // hides the popup list when a tool is selected) and call ToolGroup's implementation directly.
+ return OO.ui.ListToolGroup.super.super.prototype.onMouseKeyUp.call( this, e );
+ } else {
+ return OO.ui.ListToolGroup.super.prototype.onMouseKeyUp.call( this, e );
+ }
+};
+
+OO.ui.ListToolGroup.prototype.updateCollapsibleState = function () {
+ var i, len;
+
+ this.getExpandCollapseTool()
+ .setIcon( this.expanded ? 'collapse' : 'expand' )
+ .setTitle( OO.ui.msg( this.expanded ? 'ooui-toolgroup-collapse' : 'ooui-toolgroup-expand' ) );
+
+ for ( i = 0, len = this.collapsibleTools.length; i < len; i++ ) {
+ this.collapsibleTools[ i ].toggle( this.expanded );
+ }
+};
+
/**
* Drop down menu layout of tools as selectable menu items.
*
@@ -7408,6 +10669,12 @@ OO.ui.ListToolGroup.static.name = 'list';
* @param {Object} [config] Configuration options
*/
OO.ui.MenuToolGroup = function OoUiMenuToolGroup( toolbar, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( toolbar ) && config === undefined ) {
+ config = toolbar;
+ toolbar = config.toolbar;
+ }
+
// Configuration initialization
config = config || {};
@@ -7427,8 +10694,6 @@ OO.inheritClass( OO.ui.MenuToolGroup, OO.ui.PopupToolGroup );
/* Static Properties */
-OO.ui.MenuToolGroup.static.accelTooltips = true;
-
OO.ui.MenuToolGroup.static.name = 'menu';
/* Methods */
@@ -7444,8 +10709,8 @@ OO.ui.MenuToolGroup.prototype.onUpdateState = function () {
labelTexts = [];
for ( name in this.tools ) {
- if ( this.tools[name].isActive() ) {
- labelTexts.push( this.tools[name].getTitle() );
+ if ( this.tools[ name ].isActive() ) {
+ labelTexts.push( this.tools[ name ].getTitle() );
}
}
@@ -7461,12 +10726,18 @@ OO.ui.MenuToolGroup.prototype.onUpdateState = function () {
* @mixins OO.ui.PopupElement
*
* @constructor
- * @param {OO.ui.Toolbar} toolbar
+ * @param {OO.ui.ToolGroup} toolGroup
* @param {Object} [config] Configuration options
*/
-OO.ui.PopupTool = function OoUiPopupTool( toolbar, config ) {
+OO.ui.PopupTool = function OoUiPopupTool( toolGroup, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( toolGroup ) && config === undefined ) {
+ config = toolGroup;
+ toolGroup = config.toolGroup;
+ }
+
// Parent constructor
- OO.ui.PopupTool.super.call( this, toolbar, config );
+ OO.ui.PopupTool.super.call( this, toolGroup, config );
// Mixin constructors
OO.ui.PopupElement.call( this, config );
@@ -7507,10 +10778,108 @@ OO.ui.PopupTool.prototype.onUpdateState = function () {
};
/**
+ * Tool that has a tool group inside. This is a bad workaround for the lack of proper hierarchical
+ * menus in toolbars (T74159).
+ *
+ * @abstract
+ * @class
+ * @extends OO.ui.Tool
+ *
+ * @constructor
+ * @param {OO.ui.ToolGroup} toolGroup
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.ToolGroupTool = function OoUiToolGroupTool( toolGroup, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( toolGroup ) && config === undefined ) {
+ config = toolGroup;
+ toolGroup = config.toolGroup;
+ }
+
+ // Parent constructor
+ OO.ui.ToolGroupTool.super.call( this, toolGroup, config );
+
+ // Properties
+ this.innerToolGroup = this.createGroup( this.constructor.static.groupConfig );
+
+ // Events
+ this.innerToolGroup.connect( this, { disable: 'onToolGroupDisable' } );
+
+ // Initialization
+ this.$link.remove();
+ this.$element
+ .addClass( 'oo-ui-toolGroupTool' )
+ .append( this.innerToolGroup.$element );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.ToolGroupTool, OO.ui.Tool );
+
+/* Static Properties */
+
+/**
+ * Tool group configuration. See OO.ui.Toolbar#setup for the accepted values.
+ *
+ * @property {Object.<string,Array>}
+ */
+OO.ui.ToolGroupTool.static.groupConfig = {};
+
+/* Methods */
+
+/**
+ * Handle the tool being selected.
+ *
+ * @inheritdoc
+ */
+OO.ui.ToolGroupTool.prototype.onSelect = function () {
+ this.innerToolGroup.setActive( !this.innerToolGroup.active );
+ return false;
+};
+
+/**
+ * Synchronize disabledness state of the tool with the inner toolgroup.
+ *
+ * @private
+ * @param {boolean} disabled Element is disabled
+ */
+OO.ui.ToolGroupTool.prototype.onToolGroupDisable = function ( disabled ) {
+ this.setDisabled( disabled );
+};
+
+/**
+ * Handle the toolbar state being updated.
+ *
+ * @inheritdoc
+ */
+OO.ui.ToolGroupTool.prototype.onUpdateState = function () {
+ this.setActive( false );
+};
+
+/**
+ * Build a OO.ui.ToolGroup from the configuration.
+ *
+ * @param {Object.<string,Array>} group Tool group configuration. See OO.ui.Toolbar#setup for the
+ * accepted values.
+ * @return {OO.ui.ListToolGroup}
+ */
+OO.ui.ToolGroupTool.prototype.createGroup = function ( group ) {
+ if ( group.include === '*' ) {
+ // Apply defaults to catch-all groups
+ if ( group.label === undefined ) {
+ group.label = OO.ui.msg( 'ooui-toolbar-more' );
+ }
+ }
+
+ return this.toolbar.getToolGroupFactory().create( 'list', this.toolbar, group );
+};
+
+/**
* Mixin for OO.ui.Widget subclasses to provide OO.ui.GroupElement.
*
* Use together with OO.ui.ItemWidget to make disabled state inheritable.
*
+ * @private
* @abstract
* @class
* @extends OO.ui.GroupElement
@@ -7547,7 +10916,7 @@ OO.ui.GroupWidget.prototype.setDisabled = function ( 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();
+ this.items[ i ].updateDisabled();
}
}
@@ -7558,10 +10927,11 @@ OO.ui.GroupWidget.prototype.setDisabled = function ( disabled ) {
* Mixin for widgets used as items in widgets that inherit OO.ui.GroupWidget.
*
* Item widgets have a reference to a OO.ui.GroupWidget while they are attached to the group. This
- * allows bidrectional communication.
+ * allows bidirectional communication.
*
* Use together with OO.ui.GroupWidget to make disabled state inheritable.
*
+ * @private
* @abstract
* @class
*
@@ -7603,245 +10973,9 @@ OO.ui.ItemWidget.prototype.setElementGroup = function ( group ) {
};
/**
- * Mixin that adds a menu showing suggested values for a text input.
- *
- * Subclasses must handle `select` and `choose` 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.
- *
- * @param {jQuery.Event} e Input focus event
- */
-OO.ui.LookupInputWidget.prototype.onLookupInputFocus = function () {
- this.openLookupMenu();
-};
-
-/**
- * Handle input blur event.
- *
- * @param {jQuery.Event} e Input blur event
- */
-OO.ui.LookupInputWidget.prototype.onLookupInputBlur = function () {
- this.lookupMenu.toggle( false );
-};
-
-/**
- * Handle input mouse down event.
- *
- * @param {jQuery.Event} e Input mouse down event
- */
-OO.ui.LookupInputWidget.prototype.onLookupInputMouseDown = function () {
- this.openLookupMenu();
-};
-
-/**
- * Handle input change event.
- *
- * @param {string} value New input value
- */
-OO.ui.LookupInputWidget.prototype.onLookupInputChange = function () {
- this.openLookupMenu();
-};
-
-/**
- * Get lookup menu.
- *
- * @return {OO.ui.TextInputMenuWidget}
- */
-OO.ui.LookupInputWidget.prototype.getLookupMenu = function () {
- return this.lookupMenu;
-};
-
-/**
- * Open the menu.
- *
- * @chainable
- */
-OO.ui.LookupInputWidget.prototype.openLookupMenu = function () {
- var value = this.lookupInput.getValue();
-
- if ( this.lookupMenu.$input.is( ':focus' ) && $.trim( value ) !== '' ) {
- this.populateLookupMenu();
- this.lookupMenu.toggle( true );
- } else {
- this.lookupMenu
- .clearItems()
- .toggle( false );
- }
-
- return this;
-};
-
-/**
- * Populate lookup menu with current information.
- *
- * @chainable
- */
-OO.ui.LookupInputWidget.prototype.populateLookupMenu = function () {
- var widget = this;
-
- if ( !this.populating ) {
- this.populating = true;
- this.getLookupMenuItems()
- .done( function ( items ) {
- widget.lookupMenu.clearItems();
- if ( items.length ) {
- widget.lookupMenu
- .addItems( items )
- .toggle( true );
- widget.initializeLookupMenuSelection();
- widget.openLookupMenu();
- } else {
- widget.lookupMenu.toggle( true );
- }
- widget.populating = false;
- } )
- .fail( function () {
- widget.lookupMenu.clearItems();
- widget.populating = false;
- } );
- }
-
- return this;
-};
-
-/**
- * Set selection in the lookup menu with current information.
- *
- * @chainable
- */
-OO.ui.LookupInputWidget.prototype.initializeLookupMenuSelection = function () {
- if ( !this.lookupMenu.getSelectedItem() ) {
- this.lookupMenu.selectItem( this.lookupMenu.getFirstSelectableItem() );
- }
- this.lookupMenu.highlightItem( this.lookupMenu.getSelectedItem() );
-};
-
-/**
- * Get lookup menu items for the current query.
- *
- * @return {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 widget = this,
- 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( function () {
- widget.lookupQuery = null;
- widget.lookupRequest = null;
- } )
- .done( function ( data ) {
- widget.lookupCache[value] = widget.getLookupCacheItemFromData( data );
- deferred.resolve( widget.getLookupMenuItemsFromData( widget.lookupCache[value] ) );
- } )
- .fail( function () {
- deferred.reject();
- } );
- this.pushPending();
- this.lookupRequest.always( function () {
- widget.popPending();
- } );
- }
- }
- return deferred.promise();
-};
-
-/**
- * Get a new request object of the current lookup query value.
- *
- * @abstract
- * @return {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.
- *
- * @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.
- *
- * @abstract
- * @param {Mixed} data Cached result data, usually an array
- * @return {OO.ui.MenuItemWidget[]} Menu items
- */
-OO.ui.LookupInputWidget.prototype.getLookupMenuItemsFromData = function () {
- // Stub, implemented in subclass
- return [];
-};
-
-/**
- * Set of controls for an OO.ui.OutlineWidget.
- *
+ * OutlineControlsWidget is a set of controls for an {@link OO.ui.OutlineSelectWidget outline select widget}.
* Controls include moving items up and down, removing items, and adding different kinds of items.
+ * ####Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.####
*
* @class
* @extends OO.ui.Widget
@@ -7849,12 +10983,21 @@ OO.ui.LookupInputWidget.prototype.getLookupMenuItemsFromData = function () {
* @mixins OO.ui.IconElement
*
* @constructor
- * @param {OO.ui.OutlineWidget} outline Outline to control
+ * @param {OO.ui.OutlineSelectWidget} outline Outline to control
* @param {Object} [config] Configuration options
+ * @cfg {Object} [abilities] List of abilties
+ * @cfg {boolean} [abilities.move=true] Allow moving movable items
+ * @cfg {boolean} [abilities.remove=true] Allow removing removable items
*/
OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( outline ) && config === undefined ) {
+ config = outline;
+ outline = config.outline;
+ }
+
// Configuration initialization
- config = $.extend( { icon: 'add-item' }, config );
+ config = $.extend( { icon: 'add' }, config );
// Parent constructor
OO.ui.OutlineControlsWidget.super.call( this, config );
@@ -7865,25 +11008,23 @@ OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, confi
// Properties
this.outline = outline;
- this.$movers = this.$( '<div>' );
+ this.$movers = $( '<div>' );
this.upButton = new OO.ui.ButtonWidget( {
- $: this.$,
framed: false,
icon: 'collapse',
title: OO.ui.msg( 'ooui-outline-control-move-up' )
} );
this.downButton = new OO.ui.ButtonWidget( {
- $: this.$,
framed: false,
icon: 'expand',
title: OO.ui.msg( 'ooui-outline-control-move-down' )
} );
this.removeButton = new OO.ui.ButtonWidget( {
- $: this.$,
framed: false,
icon: 'remove',
title: OO.ui.msg( 'ooui-outline-control-remove' )
} );
+ this.abilities = { move: true, remove: true };
// Events
outline.connect( this, {
@@ -7902,6 +11043,7 @@ OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, confi
.addClass( 'oo-ui-outlineControlsWidget-movers' )
.append( this.removeButton.$element, this.upButton.$element, this.downButton.$element );
this.$element.append( this.$icon, this.$group, this.$movers );
+ this.setAbilities( config.abilities || {} );
};
/* Setup */
@@ -7924,28 +11066,49 @@ OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.IconElement );
/* Methods */
/**
+ * Set abilities.
+ *
+ * @param {Object} abilities List of abilties
+ * @param {boolean} [abilities.move] Allow moving movable items
+ * @param {boolean} [abilities.remove] Allow removing removable items
+ */
+OO.ui.OutlineControlsWidget.prototype.setAbilities = function ( abilities ) {
+ var ability;
+
+ for ( ability in this.abilities ) {
+ if ( abilities[ability] !== undefined ) {
+ this.abilities[ability] = !!abilities[ability];
+ }
+ }
+
+ this.onOutlineChange();
+};
+
+/**
+ *
+ * @private
* Handle outline change events.
*/
OO.ui.OutlineControlsWidget.prototype.onOutlineChange = function () {
var i, len, firstMovable, lastMovable,
items = this.outline.getItems(),
selectedItem = this.outline.getSelectedItem(),
- movable = selectedItem && selectedItem.isMovable(),
- removable = selectedItem && selectedItem.isRemovable();
+ movable = this.abilities.move && selectedItem && selectedItem.isMovable(),
+ removable = this.abilities.remove && selectedItem && selectedItem.isRemovable();
if ( movable ) {
i = -1;
len = items.length;
while ( ++i < len ) {
- if ( items[i].isMovable() ) {
- firstMovable = items[i];
+ if ( items[ i ].isMovable() ) {
+ firstMovable = items[ i ];
break;
}
}
i = len;
while ( i-- ) {
- if ( items[i].isMovable() ) {
- lastMovable = items[i];
+ if ( items[ i ].isMovable() ) {
+ lastMovable = items[ i ];
break;
}
}
@@ -7956,19 +11119,25 @@ OO.ui.OutlineControlsWidget.prototype.onOutlineChange = function () {
};
/**
- * Mixin for widgets with a boolean on/off state.
+ * ToggleWidget implements basic behavior of widgets with an on/off state.
+ * Please see OO.ui.ToggleButtonWidget and OO.ui.ToggleSwitchWidget for examples.
*
* @abstract
* @class
+ * @extends OO.ui.Widget
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] Initial value
+ * @cfg {boolean} [value=false] The toggle’s initial on/off state.
+ * By default, the toggle is in the 'off' state.
*/
OO.ui.ToggleWidget = function OoUiToggleWidget( config ) {
// Configuration initialization
config = config || {};
+ // Parent constructor
+ OO.ui.ToggleWidget.super.call( this, config );
+
// Properties
this.value = null;
@@ -7977,28 +11146,35 @@ OO.ui.ToggleWidget = function OoUiToggleWidget( config ) {
this.setValue( !!config.value );
};
+/* Setup */
+
+OO.inheritClass( OO.ui.ToggleWidget, OO.ui.Widget );
+
/* Events */
/**
* @event change
- * @param {boolean} value Changed value
+ *
+ * A change event is emitted when the on/off state of the toggle changes.
+ *
+ * @param {boolean} value Value representing the new state of the toggle
*/
/* Methods */
/**
- * Get the value of the toggle.
+ * Get the value representing the toggle’s state.
*
- * @return {boolean}
+ * @return {boolean} The on/off state of the toggle
*/
OO.ui.ToggleWidget.prototype.getValue = function () {
return this.value;
};
/**
- * Set the value of the toggle.
+ * Set the state of the toggle: `true` for 'on', `false' for 'off'.
*
- * @param {boolean} value New value
+ * @param {boolean} value The state of the toggle
* @fires change
* @chainable
*/
@@ -8009,14 +11185,34 @@ OO.ui.ToggleWidget.prototype.setValue = function ( value ) {
this.emit( 'change', value );
this.$element.toggleClass( 'oo-ui-toggleWidget-on', value );
this.$element.toggleClass( 'oo-ui-toggleWidget-off', !value );
+ this.$element.attr( 'aria-checked', value.toString() );
}
return this;
};
/**
- * Group widget for multiple related buttons.
- *
- * Use together with OO.ui.ButtonWidget.
+ * A ButtonGroupWidget groups related buttons and is used together with OO.ui.ButtonWidget and
+ * its subclasses. Each button in a group is addressed by a unique reference. Buttons can be added,
+ * removed, and cleared from the group.
+ *
+ * @example
+ * // Example: A ButtonGroupWidget with two buttons
+ * var button1 = new OO.ui.PopupButtonWidget( {
+ * label: 'Select a category',
+ * icon: 'menu',
+ * popup: {
+ * $content: $( '<p>List of categories...</p>' ),
+ * padded: true,
+ * align: 'left'
+ * }
+ * } );
+ * var button2 = new OO.ui.ButtonWidget( {
+ * label: 'Add item'
+ * });
+ * var buttonGroup = new OO.ui.ButtonGroupWidget( {
+ * items: [button1, button2]
+ * } );
+ * $( 'body' ).append( buttonGroup.$element );
*
* @class
* @extends OO.ui.Widget
@@ -8024,9 +11220,12 @@ OO.ui.ToggleWidget.prototype.setValue = function ( value ) {
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {OO.ui.ButtonWidget} [items] Buttons to add
+ * @cfg {OO.ui.ButtonWidget[]} [items] Buttons to add
*/
OO.ui.ButtonGroupWidget = function OoUiButtonGroupWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
// Parent constructor
OO.ui.ButtonGroupWidget.super.call( this, config );
@@ -8035,7 +11234,7 @@ OO.ui.ButtonGroupWidget = function OoUiButtonGroupWidget( config ) {
// Initialization
this.$element.addClass( 'oo-ui-buttonGroupWidget' );
- if ( $.isArray( config.items ) ) {
+ if ( Array.isArray( config.items ) ) {
this.addItems( config.items );
}
};
@@ -8046,7 +11245,23 @@ OO.inheritClass( OO.ui.ButtonGroupWidget, OO.ui.Widget );
OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.GroupElement );
/**
- * Generic widget for buttons.
+ * ButtonWidget is a generic widget for buttons. A wide variety of looks,
+ * feels, and functionality can be customized via the class’s configuration options
+ * and methods. Please see the [OOjs UI documentation on MediaWiki] [1] for more information
+ * and examples.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Buttons_and_Switches
+ *
+ * @example
+ * // A button widget
+ * var button = new OO.ui.ButtonWidget( {
+ * label: 'Button with Icon',
+ * icon: 'remove',
+ * iconTitle: 'Remove'
+ * } );
+ * $( 'body' ).append( button.$element );
+ *
+ * NOTE: HTML form buttons should use the OO.ui.ButtonInputWidget class.
*
* @class
* @extends OO.ui.Widget
@@ -8056,15 +11271,17 @@ OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.GroupElement );
* @mixins OO.ui.LabelElement
* @mixins OO.ui.TitledElement
* @mixins OO.ui.FlaggedElement
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {string} [href] Hyperlink to visit when clicked
- * @cfg {string} [target] Target to open hyperlink in
+ * @cfg {string} [href] Hyperlink to visit when the button is clicked.
+ * @cfg {string} [target] The frame or window in which to open the hyperlink.
+ * @cfg {boolean} [noFollow] Search engine traversal hint (default: true)
*/
OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
// Configuration initialization
- config = $.extend( { target: '_blank' }, config );
+ config = config || {};
// Parent constructor
OO.ui.ButtonWidget.super.call( this, config );
@@ -8074,19 +11291,17 @@ OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
OO.ui.IconElement.call( this, config );
OO.ui.IndicatorElement.call( this, config );
OO.ui.LabelElement.call( this, config );
- OO.ui.TitledElement.call( this, config, $.extend( {}, config, { $titled: this.$button } ) );
+ OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$button } ) );
OO.ui.FlaggedElement.call( this, config );
+ OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$button } ) );
// Properties
this.href = null;
this.target = null;
- this.isHyperlink = false;
+ this.noFollow = false;
// Events
- this.$button.on( {
- click: OO.ui.bind( this.onClick, this ),
- keypress: OO.ui.bind( this.onKeyPress, this )
- } );
+ this.connect( this, { disable: 'onDisable' } );
// Initialization
this.$button.append( this.$icon, this.$label, this.$indicator );
@@ -8095,6 +11310,7 @@ OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
.append( this.$button );
this.setHref( config.href );
this.setTarget( config.target );
+ this.setNoFollow( config.noFollow );
};
/* Setup */
@@ -8106,45 +11322,32 @@ OO.mixinClass( OO.ui.ButtonWidget, OO.ui.IndicatorElement );
OO.mixinClass( OO.ui.ButtonWidget, OO.ui.LabelElement );
OO.mixinClass( OO.ui.ButtonWidget, OO.ui.TitledElement );
OO.mixinClass( OO.ui.ButtonWidget, OO.ui.FlaggedElement );
-
-/* Events */
-
-/**
- * @event click
- */
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.TabIndexedElement );
/* Methods */
/**
- * Handles mouse click events.
- *
- * @param {jQuery.Event} e Mouse click event
- * @fires click
+ * @inheritdoc
*/
-OO.ui.ButtonWidget.prototype.onClick = function () {
+OO.ui.ButtonWidget.prototype.onMouseDown = function ( e ) {
if ( !this.isDisabled() ) {
- this.emit( 'click' );
- if ( this.isHyperlink ) {
- return true;
- }
+ // Remove the tab-index while the button is down to prevent the button from stealing focus
+ this.$button.removeAttr( 'tabindex' );
}
- return false;
+
+ return OO.ui.ButtonElement.prototype.onMouseDown.call( this, e );
};
/**
- * Handles keypress events.
- *
- * @param {jQuery.Event} e Keypress event
- * @fires click
+ * @inheritdoc
*/
-OO.ui.ButtonWidget.prototype.onKeyPress = function ( e ) {
- if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
- this.onClick();
- if ( this.isHyperlink ) {
- return true;
- }
+OO.ui.ButtonWidget.prototype.onMouseUp = function ( e ) {
+ if ( !this.isDisabled() ) {
+ // Restore the tab-index after the button is up to restore the button's accessibility
+ this.$button.attr( 'tabindex', this.tabIndex );
}
- return false;
+
+ return OO.ui.ButtonElement.prototype.onMouseUp.call( this, e );
};
/**
@@ -8166,6 +11369,15 @@ OO.ui.ButtonWidget.prototype.getTarget = function () {
};
/**
+ * Get search engine traversal hint.
+ *
+ * @return {boolean} Whether search engines should avoid traversing this hyperlink
+ */
+OO.ui.ButtonWidget.prototype.getNoFollow = function () {
+ return this.noFollow;
+};
+
+/**
* Set hyperlink location.
*
* @param {string|null} href Hyperlink location, null to remove
@@ -8175,19 +11387,40 @@ OO.ui.ButtonWidget.prototype.setHref = function ( href ) {
if ( href !== this.href ) {
this.href = href;
- if ( href !== null ) {
- this.$button.attr( 'href', href );
- this.isHyperlink = true;
- } else {
- this.$button.removeAttr( 'href' );
- this.isHyperlink = false;
- }
+ this.updateHref();
+ }
+
+ return this;
+};
+
+/**
+ * Update the `href` attribute, in case of changes to href or
+ * disabled state.
+ *
+ * @private
+ * @chainable
+ */
+OO.ui.ButtonWidget.prototype.updateHref = function () {
+ if ( this.href !== null && !this.isDisabled() ) {
+ this.$button.attr( 'href', this.href );
+ } else {
+ this.$button.removeAttr( 'href' );
}
return this;
};
/**
+ * Handle disable events.
+ *
+ * @private
+ * @param {boolean} disabled Element is disabled
+ */
+OO.ui.ButtonWidget.prototype.onDisable = function () {
+ this.updateHref();
+};
+
+/**
* Set hyperlink target.
*
* @param {string|null} target Hyperlink target, null to remove
@@ -8208,7 +11441,35 @@ OO.ui.ButtonWidget.prototype.setTarget = function ( target ) {
};
/**
- * Button widget that executes an action and is managed by an OO.ui.ActionSet.
+ * Set search engine traversal hint.
+ *
+ * @param {boolean} noFollow True if search engines should avoid traversing this hyperlink
+ */
+OO.ui.ButtonWidget.prototype.setNoFollow = function ( noFollow ) {
+ noFollow = typeof noFollow === 'boolean' ? noFollow : true;
+
+ if ( noFollow !== this.noFollow ) {
+ this.noFollow = noFollow;
+ if ( noFollow ) {
+ this.$button.attr( 'rel', 'nofollow' );
+ } else {
+ this.$button.removeAttr( 'rel' );
+ }
+ }
+
+ return this;
+};
+
+/**
+ * An ActionWidget is a {@link OO.ui.ButtonWidget button widget} that executes an action.
+ * Action widgets are used with OO.ui.ActionSet, which manages the behavior and availability
+ * of the actions.
+ *
+ * Both actions and action sets are primarily used with {@link OO.ui.Dialog Dialogs}.
+ * Please see the [OOjs UI documentation on MediaWiki] [1] for more information
+ * and examples.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Windows/Process_Dialogs#Action_sets
*
* @class
* @extends OO.ui.ButtonWidget
@@ -8216,11 +11477,14 @@ OO.ui.ButtonWidget.prototype.setTarget = function ( target ) {
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {string} [action] Symbolic action name
- * @cfg {string[]} [modes] Symbolic mode names
+ * @cfg {string} [action] Symbolic name of the action (e.g., ‘continue’ or ‘cancel’).
+ * @cfg {string[]} [modes] Symbolic names of the modes (e.g., ‘edit’ or ‘read’) in which the action
+ * should be made available. See the action set's {@link OO.ui.ActionSet#setMode setMode} method
+ * for more information about setting modes.
+ * @cfg {boolean} [framed=false] Render the action button with a frame
*/
OO.ui.ActionWidget = function OoUiActionWidget( config ) {
- // Config intialization
+ // Configuration initialization
config = $.extend( { framed: false }, config );
// Parent constructor
@@ -8247,23 +11511,25 @@ OO.mixinClass( OO.ui.ActionWidget, OO.ui.PendingElement );
/* Events */
/**
+ * A resize event is emitted when the size of the widget changes.
+ *
* @event resize
*/
/* Methods */
/**
- * Check if action is available in a certain mode.
+ * Check if the action is configured to be available in the specified `mode`.
*
* @param {string} mode Name of mode
- * @return {boolean} Has mode
+ * @return {boolean} The action is configured with the mode
*/
OO.ui.ActionWidget.prototype.hasMode = function ( mode ) {
return this.modes.indexOf( mode ) !== -1;
};
/**
- * Get symbolic action name.
+ * Get the symbolic name of the action (e.g., ‘continue’ or ‘cancel’).
*
* @return {string}
*/
@@ -8272,9 +11538,13 @@ OO.ui.ActionWidget.prototype.getAction = function () {
};
/**
- * Get symbolic action name.
+ * Get the symbolic name of the mode or modes for which the action is configured to be available.
*
- * @return {string}
+ * The current mode is set with the action set's {@link OO.ui.ActionSet#setMode setMode} method.
+ * Only actions that are configured to be avaiable in the current mode will be visible. All other actions
+ * are hidden.
+ *
+ * @return {string[]}
*/
OO.ui.ActionWidget.prototype.getModes = function () {
return this.modes.slice();
@@ -8283,6 +11553,7 @@ OO.ui.ActionWidget.prototype.getModes = function () {
/**
* Emit a resize event if the size has changed.
*
+ * @private
* @chainable
*/
OO.ui.ActionWidget.prototype.propagateResize = function () {
@@ -8347,7 +11618,7 @@ OO.ui.ActionWidget.prototype.clearFlags = function () {
};
/**
- * Toggle visibility of button.
+ * Toggle the visibility of the action button.
*
* @param {boolean} [show] Show button, omit to toggle visibility
* @chainable
@@ -8361,7 +11632,22 @@ OO.ui.ActionWidget.prototype.toggle = function () {
};
/**
- * Button that shows and hides a popup.
+ * PopupButtonWidgets toggle the visibility of a contained {@link OO.ui.PopupWidget PopupWidget},
+ * which is used to display additional information or options.
+ *
+ * @example
+ * // Example of a popup button.
+ * var popupButton = new OO.ui.PopupButtonWidget( {
+ * label: 'Popup button with options',
+ * icon: 'menu',
+ * popup: {
+ * $content: $( '<p>Additional options here.</p>' ),
+ * padded: true,
+ * align: 'force-left'
+ * }
+ * } );
+ * // Append the button to the DOM.
+ * $( 'body' ).append( popupButton.$element );
*
* @class
* @extends OO.ui.ButtonWidget
@@ -8377,9 +11663,13 @@ OO.ui.PopupButtonWidget = function OoUiPopupButtonWidget( config ) {
// Mixin constructors
OO.ui.PopupElement.call( this, config );
+ // Events
+ this.connect( this, { click: 'onAction' } );
+
// Initialization
this.$element
.addClass( 'oo-ui-popupButtonWidget' )
+ .attr( 'aria-haspopup', 'true' )
.append( this.popup.$element );
};
@@ -8391,34 +11681,50 @@ OO.mixinClass( OO.ui.PopupButtonWidget, OO.ui.PopupElement );
/* Methods */
/**
- * Handles mouse click events.
+ * Handle the button action being triggered.
*
- * @param {jQuery.Event} e Mouse click event
+ * @private
*/
-OO.ui.PopupButtonWidget.prototype.onClick = function ( e ) {
- // Skip clicks within the popup
- if ( $.contains( this.popup.$element[0], e.target ) ) {
- return;
- }
-
- if ( !this.isDisabled() ) {
- this.popup.toggle();
- // Parent method
- OO.ui.PopupButtonWidget.super.prototype.onClick.call( this );
- }
- return false;
+OO.ui.PopupButtonWidget.prototype.onAction = function () {
+ this.popup.toggle();
};
/**
- * Button that toggles on and off.
+ * ToggleButtons are buttons that have a state (‘on’ or ‘off’) that is represented by a
+ * Boolean value. Like other {@link OO.ui.ButtonWidget buttons}, toggle buttons can be
+ * configured with {@link OO.ui.IconElement icons}, {@link OO.ui.IndicatorElement indicators},
+ * {@link OO.ui.TitledElement titles}, {@link OO.ui.FlaggedElement styling flags},
+ * and {@link OO.ui.LabelElement labels}. Please see
+ * the [OOjs UI documentation][1] on MediaWiki for more information.
+ *
+ * @example
+ * // Toggle buttons in the 'off' and 'on' state.
+ * var toggleButton1 = new OO.ui.ToggleButtonWidget( {
+ * label: 'Toggle Button off'
+ * } );
+ * var toggleButton2 = new OO.ui.ToggleButtonWidget( {
+ * label: 'Toggle Button on',
+ * value: true
+ * } );
+ * // Append the buttons to the DOM.
+ * $( 'body' ).append( toggleButton1.$element, toggleButton2.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Buttons_and_Switches#Toggle_buttons
*
* @class
- * @extends OO.ui.ButtonWidget
- * @mixins OO.ui.ToggleWidget
+ * @extends OO.ui.ToggleWidget
+ * @mixins OO.ui.ButtonElement
+ * @mixins OO.ui.IconElement
+ * @mixins OO.ui.IndicatorElement
+ * @mixins OO.ui.LabelElement
+ * @mixins OO.ui.TitledElement
+ * @mixins OO.ui.FlaggedElement
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] Initial value
+ * @cfg {boolean} [value=false] The toggle button’s initial on/off
+ * state. By default, the button is in the 'off' state.
*/
OO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {
// Configuration initialization
@@ -8428,29 +11734,44 @@ OO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {
OO.ui.ToggleButtonWidget.super.call( this, config );
// Mixin constructors
- OO.ui.ToggleWidget.call( this, config );
+ OO.ui.ButtonElement.call( this, config );
+ OO.ui.IconElement.call( this, config );
+ OO.ui.IndicatorElement.call( this, config );
+ OO.ui.LabelElement.call( this, config );
+ OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$button } ) );
+ OO.ui.FlaggedElement.call( this, config );
+ OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$button } ) );
+
+ // Events
+ this.connect( this, { click: 'onAction' } );
// Initialization
- this.$element.addClass( 'oo-ui-toggleButtonWidget' );
+ this.$button.append( this.$icon, this.$label, this.$indicator );
+ this.$element
+ .addClass( 'oo-ui-toggleButtonWidget' )
+ .append( this.$button );
};
/* Setup */
-OO.inheritClass( OO.ui.ToggleButtonWidget, OO.ui.ButtonWidget );
-OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.ToggleWidget );
+OO.inheritClass( OO.ui.ToggleButtonWidget, OO.ui.ToggleWidget );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.ButtonElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.IconElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.IndicatorElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.LabelElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.TitledElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.FlaggedElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.TabIndexedElement );
/* Methods */
/**
- * @inheritdoc
+ * Handle the button action being triggered.
+ *
+ * @private
*/
-OO.ui.ToggleButtonWidget.prototype.onClick = function () {
- if ( !this.isDisabled() ) {
- this.setValue( !this.value );
- }
-
- // Parent method
- return OO.ui.ToggleButtonWidget.super.prototype.onClick.call( this );
+OO.ui.ToggleButtonWidget.prototype.onAction = function () {
+ this.setValue( !this.value );
};
/**
@@ -8459,98 +11780,62 @@ OO.ui.ToggleButtonWidget.prototype.onClick = function () {
OO.ui.ToggleButtonWidget.prototype.setValue = function ( value ) {
value = !!value;
if ( value !== this.value ) {
+ // Might be called from parent constructor before ButtonElement constructor
+ if ( this.$button ) {
+ this.$button.attr( 'aria-pressed', value.toString() );
+ }
this.setActive( value );
}
- // Parent method (from mixin)
- OO.ui.ToggleWidget.prototype.setValue.call( this, value );
+ // Parent method
+ OO.ui.ToggleButtonWidget.super.prototype.setValue.call( this, value );
return this;
};
/**
- * Icon widget.
- *
- * See OO.ui.IconElement for more information.
- *
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.TitledElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
+ * @inheritdoc
*/
-OO.ui.IconWidget = function OoUiIconWidget( config ) {
- // Config intialization
- config = config || {};
-
- // Parent constructor
- OO.ui.IconWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.IconElement.call( this, $.extend( {}, config, { $icon: this.$element } ) );
- OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$element } ) );
-
- // Initialization
- this.$element.addClass( 'oo-ui-iconWidget' );
+OO.ui.ToggleButtonWidget.prototype.setButtonElement = function ( $button ) {
+ if ( this.$button ) {
+ this.$button.removeAttr( 'aria-pressed' );
+ }
+ OO.ui.ButtonElement.prototype.setButtonElement.call( this, $button );
+ this.$button.attr( 'aria-pressed', this.value.toString() );
};
-/* Setup */
-
-OO.inheritClass( OO.ui.IconWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.IconWidget, OO.ui.IconElement );
-OO.mixinClass( OO.ui.IconWidget, OO.ui.TitledElement );
-
-/* Static Properties */
-
-OO.ui.IconWidget.static.tagName = 'span';
-
/**
- * Indicator widget.
+ * DropdownWidgets are not menus themselves, rather they contain a menu of options created with
+ * OO.ui.MenuOptionWidget. The DropdownWidget takes care of opening and displaying the menu so that
+ * users can interact with it.
*
- * See OO.ui.IndicatorElement for more information.
+ * @example
+ * // Example: A DropdownWidget with a menu that contains three options
+ * var dropDown = new OO.ui.DropdownWidget( {
+ * label: 'Dropdown menu: Select a menu option',
+ * menu: {
+ * items: [
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'a',
+ * label: 'First'
+ * } ),
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'b',
+ * label: 'Second'
+ * } ),
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'c',
+ * label: 'Third'
+ * } )
+ * ]
+ * }
+ * } );
*
- * @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.TitledElement
- *
- * @constructor
- * @param {Object} [config] Configuration options
- */
-OO.ui.IndicatorWidget = function OoUiIndicatorWidget( config ) {
- // Config intialization
- config = config || {};
-
- // Parent constructor
- OO.ui.IndicatorWidget.super.call( this, config );
-
- // Mixin constructors
- OO.ui.IndicatorElement.call( this, $.extend( {}, config, { $indicator: this.$element } ) );
- OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$element } ) );
-
- // Initialization
- this.$element.addClass( 'oo-ui-indicatorWidget' );
-};
-
-/* Setup */
-
-OO.inheritClass( OO.ui.IndicatorWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.IndicatorElement );
-OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.TitledElement );
-
-/* Static Properties */
-
-OO.ui.IndicatorWidget.static.tagName = 'span';
-
-/**
- * Inline menu of options.
+ * $( 'body' ).append( dropDown.$element );
*
- * Inline menus provide a control for accessing a menu and compose a menu within the widget, which
- * can be accessed using the #getMenu method.
+ * For more information, please see the [OOjs UI documentation on MediaWiki] [1].
*
- * Use with OO.ui.MenuOptionWidget.
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
*
* @class
* @extends OO.ui.Widget
@@ -8558,66 +11843,75 @@ OO.ui.IndicatorWidget.static.tagName = 'span';
* @mixins OO.ui.IndicatorElement
* @mixins OO.ui.LabelElement
* @mixins OO.ui.TitledElement
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
* @cfg {Object} [menu] Configuration options to pass to menu widget
*/
-OO.ui.InlineMenuWidget = function OoUiInlineMenuWidget( config ) {
+OO.ui.DropdownWidget = function OoUiDropdownWidget( config ) {
// Configuration initialization
config = $.extend( { indicator: 'down' }, config );
// Parent constructor
- OO.ui.InlineMenuWidget.super.call( this, config );
+ OO.ui.DropdownWidget.super.call( this, config );
+
+ // Properties (must be set before TabIndexedElement constructor call)
+ this.$handle = this.$( '<span>' );
// Mixin constructors
OO.ui.IconElement.call( this, config );
OO.ui.IndicatorElement.call( this, config );
OO.ui.LabelElement.call( this, config );
OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$label } ) );
+ OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$handle } ) );
// Properties
- this.menu = new OO.ui.MenuWidget( $.extend( { $: this.$, widget: this }, config.menu ) );
- this.$handle = this.$( '<span>' );
+ this.menu = new OO.ui.MenuSelectWidget( $.extend( { widget: this }, config.menu ) );
// Events
- this.$element.on( { click: OO.ui.bind( this.onClick, this ) } );
+ this.$handle.on( {
+ click: this.onClick.bind( this ),
+ keypress: this.onKeyPress.bind( this )
+ } );
this.menu.connect( this, { select: 'onMenuSelect' } );
// Initialization
this.$handle
- .addClass( 'oo-ui-inlineMenuWidget-handle' )
+ .addClass( 'oo-ui-dropdownWidget-handle' )
.append( this.$icon, this.$label, this.$indicator );
this.$element
- .addClass( 'oo-ui-inlineMenuWidget' )
+ .addClass( 'oo-ui-dropdownWidget' )
.append( this.$handle, this.menu.$element );
};
/* Setup */
-OO.inheritClass( OO.ui.InlineMenuWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.IconElement );
-OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.IndicatorElement );
-OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.InlineMenuWidget, OO.ui.TitledElement );
+OO.inheritClass( OO.ui.DropdownWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.DropdownWidget, OO.ui.IconElement );
+OO.mixinClass( OO.ui.DropdownWidget, OO.ui.IndicatorElement );
+OO.mixinClass( OO.ui.DropdownWidget, OO.ui.LabelElement );
+OO.mixinClass( OO.ui.DropdownWidget, OO.ui.TitledElement );
+OO.mixinClass( OO.ui.DropdownWidget, OO.ui.TabIndexedElement );
/* Methods */
/**
* Get the menu.
*
- * @return {OO.ui.MenuWidget} Menu of widget
+ * @return {OO.ui.MenuSelectWidget} Menu of widget
*/
-OO.ui.InlineMenuWidget.prototype.getMenu = function () {
+OO.ui.DropdownWidget.prototype.getMenu = function () {
return this.menu;
};
/**
* Handles menu select events.
*
- * @param {OO.ui.MenuItemWidget} item Selected menu item
+ * @private
+ * @param {OO.ui.MenuOptionWidget} item Selected menu item
*/
-OO.ui.InlineMenuWidget.prototype.onMenuSelect = function ( item ) {
+OO.ui.DropdownWidget.prototype.onMenuSelect = function ( item ) {
var selectedLabel;
if ( !item ) {
@@ -8635,43 +11929,163 @@ OO.ui.InlineMenuWidget.prototype.onMenuSelect = function ( item ) {
};
/**
- * Handles mouse click events.
+ * Handle mouse click events.
*
+ * @private
* @param {jQuery.Event} e Mouse click event
*/
-OO.ui.InlineMenuWidget.prototype.onClick = function ( e ) {
- // Skip clicks within the menu
- if ( $.contains( this.menu.$element[0], e.target ) ) {
- return;
+OO.ui.DropdownWidget.prototype.onClick = function ( e ) {
+ if ( !this.isDisabled() && e.which === 1 ) {
+ this.menu.toggle();
}
+ return false;
+};
- if ( !this.isDisabled() ) {
- if ( this.menu.isVisible() ) {
- this.menu.toggle( false );
- } else {
- this.menu.toggle( true );
- }
+/**
+ * Handle key press events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key press event
+ */
+OO.ui.DropdownWidget.prototype.onKeyPress = function ( e ) {
+ if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
+ this.menu.toggle();
+ return false;
}
- return false;
};
/**
- * Base class for input widgets.
+ * IconWidget is a generic widget for {@link OO.ui.IconElement icons}. In general, IconWidgets should be used with OO.ui.LabelWidget,
+ * which creates a label that identifies the icon’s function. See the [OOjs UI documentation on MediaWiki] [1]
+ * for a list of icons included in the library.
+ *
+ * @example
+ * // An icon widget with a label
+ * var myIcon = new OO.ui.IconWidget( {
+ * icon: 'help',
+ * iconTitle: 'Help'
+ * } );
+ * // Create a label.
+ * var iconLabel = new OO.ui.LabelWidget( {
+ * label: 'Help'
+ * } );
+ * $( 'body' ).append( myIcon.$element, iconLabel.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Icons
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.IconElement
+ * @mixins OO.ui.TitledElement
+ * @mixins OO.ui.FlaggedElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.IconWidget = function OoUiIconWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.IconWidget.super.call( this, config );
+
+ // Mixin constructors
+ OO.ui.IconElement.call( this, $.extend( {}, config, { $icon: this.$element } ) );
+ OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$element } ) );
+ OO.ui.FlaggedElement.call( this, $.extend( {}, config, { $flagged: this.$element } ) );
+
+ // Initialization
+ this.$element.addClass( 'oo-ui-iconWidget' );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.IconWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.IconWidget, OO.ui.IconElement );
+OO.mixinClass( OO.ui.IconWidget, OO.ui.TitledElement );
+OO.mixinClass( OO.ui.IconWidget, OO.ui.FlaggedElement );
+
+/* Static Properties */
+
+OO.ui.IconWidget.static.tagName = 'span';
+
+/**
+ * IndicatorWidgets create indicators, which are small graphics that are generally used to draw
+ * attention to the status of an item or to clarify the function of a control. For a list of
+ * indicators included in the library, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * @example
+ * // Example of an indicator widget
+ * var indicator1 = new OO.ui.IndicatorWidget( {
+ * indicator: 'alert'
+ * } );
+ *
+ * // Create a fieldset layout to add a label
+ * var fieldset = new OO.ui.FieldsetLayout();
+ * fieldset.addItems( [
+ * new OO.ui.FieldLayout( indicator1, { label: 'An alert indicator:' } )
+ * ] );
+ * $( 'body' ).append( fieldset.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Icons,_Indicators,_and_Labels#Indicators
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.IndicatorElement
+ * @mixins OO.ui.TitledElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.IndicatorWidget = function OoUiIndicatorWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.IndicatorWidget.super.call( this, config );
+
+ // Mixin constructors
+ OO.ui.IndicatorElement.call( this, $.extend( {}, config, { $indicator: this.$element } ) );
+ OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$element } ) );
+
+ // Initialization
+ this.$element.addClass( 'oo-ui-indicatorWidget' );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.IndicatorWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.IndicatorElement );
+OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.TitledElement );
+
+/* Static Properties */
+
+OO.ui.IndicatorWidget.static.tagName = 'span';
+
+/**
+ * InputWidget is the base class for all input widgets, which
+ * include {@link OO.ui.TextInputWidget text inputs}, {@link OO.ui.CheckboxInputWidget checkbox inputs},
+ * {@link OO.ui.RadioInputWidget radio inputs}, and {@link OO.ui.ButtonInputWidget button inputs}.
+ * See the [OOjs UI documentation on MediaWiki] [1] for more information and examples.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
*
* @abstract
* @class
* @extends OO.ui.Widget
+ * @mixins OO.ui.FlaggedElement
+ * @mixins OO.ui.TabIndexedElement
*
* @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.
+ * @cfg {string} [name=''] The value of the input’s HTML `name` attribute.
+ * @cfg {string} [value=''] The value of the input.
+ * @cfg {Function} [inputFilter] The name of an input filter function. Input filters modify the value of an input
+ * before it is accepted.
*/
OO.ui.InputWidget = function OoUiInputWidget( config ) {
- // Config intialization
- config = $.extend( { readOnly: false }, config );
+ // Configuration initialization
+ config = config || {};
// Parent constructor
OO.ui.InputWidget.super.call( this, config );
@@ -8679,30 +12093,37 @@ OO.ui.InputWidget = function OoUiInputWidget( config ) {
// Properties
this.$input = this.getInputElement( config );
this.value = '';
- this.readOnly = false;
this.inputFilter = config.inputFilter;
+ // Mixin constructors
+ OO.ui.FlaggedElement.call( this, config );
+ OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$input } ) );
+
// Events
- this.$input.on( 'keydown mouseup cut paste change input select', OO.ui.bind( this.onEdit, this ) );
+ this.$input.on( 'keydown mouseup cut paste change input select', this.onEdit.bind( this ) );
// Initialization
this.$input
.attr( 'name', config.name )
.prop( 'disabled', this.isDisabled() );
- this.setReadOnly( config.readOnly );
- this.$element.addClass( 'oo-ui-inputWidget' ).append( this.$input );
+ this.$element.addClass( 'oo-ui-inputWidget' ).append( this.$input, $( '<span>' ) );
this.setValue( config.value );
};
/* Setup */
OO.inheritClass( OO.ui.InputWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.InputWidget, OO.ui.FlaggedElement );
+OO.mixinClass( OO.ui.InputWidget, OO.ui.TabIndexedElement );
/* Events */
/**
* @event change
- * @param value
+ *
+ * A change event is emitted when the value of the input changes.
+ *
+ * @param {string} value
*/
/* Methods */
@@ -8710,16 +12131,21 @@ OO.inheritClass( OO.ui.InputWidget, OO.ui.Widget );
/**
* Get input element.
*
- * @param {Object} [config] Configuration options
+ * Subclasses of OO.ui.InputWidget use the `config` parameter to produce different elements in
+ * different circumstances. The element must have a `value` property (like form elements).
+ *
+ * @private
+ * @param {Object} config Configuration options
* @return {jQuery} Input element
*/
OO.ui.InputWidget.prototype.getInputElement = function () {
- return this.$( '<input>' );
+ return $( '<input>' );
};
/**
* Handle potentially value-changing events.
*
+ * @private
* @param {jQuery.Event} e Key down, mouse up, cut, paste, change, input, or select event
*/
OO.ui.InputWidget.prototype.onEdit = function () {
@@ -8738,22 +12164,23 @@ OO.ui.InputWidget.prototype.onEdit = function () {
* @return {string} Input value
*/
OO.ui.InputWidget.prototype.getValue = function () {
+ // Resynchronize our internal data with DOM data. Other scripts executing on the page can modify
+ // it, and we won't know unless they're kind enough to trigger a 'change' event.
+ var value = this.$input.val();
+ if ( this.value !== value ) {
+ this.setValue( value );
+ }
return this.value;
};
/**
- * Sets the direction of the current input, either RTL or LTR
+ * Set the direction of the input, either RTL (right-to-left) or LTR (left-to-right).
*
* @param {boolean} isRTL
+ * Direction is right-to-left
*/
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' );
- }
+ this.$input.prop( 'dir', isRTL ? 'rtl' : 'ltr' );
};
/**
@@ -8764,28 +12191,29 @@ OO.ui.InputWidget.prototype.setRTL = function ( isRTL ) {
* @chainable
*/
OO.ui.InputWidget.prototype.setValue = function ( value ) {
- value = this.sanitizeValue( value );
+ value = this.cleanUpValue( value );
+ // Update the DOM if it has changed. Note that with cleanUpValue, it
+ // is possible for the DOM value to change without this.value changing.
+ if ( this.$input.val() !== value ) {
+ this.$input.val( 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.
+ * Clean up incoming value.
*
- * Ensures value is a string, and converts undefined and null to empty strings.
+ * Ensures value is a string, and converts undefined and null to empty string.
*
+ * @private
* @param {string} value Original value
- * @return {string} Sanitized value
+ * @return {string} Cleaned up value
*/
-OO.ui.InputWidget.prototype.sanitizeValue = function ( value ) {
+OO.ui.InputWidget.prototype.cleanUpValue = function ( value ) {
if ( value === undefined || value === null ) {
return '';
} else if ( this.inputFilter ) {
@@ -8796,159 +12224,572 @@ OO.ui.InputWidget.prototype.sanitizeValue = function ( value ) {
};
/**
- * Simulate the behavior of clicking on a label bound to this input.
+ * Simulate the behavior of clicking on a label bound to this input. This method is only called by
+ * {@link OO.ui.LabelWidget LabelWidget} and {@link OO.ui.FieldLayout FieldLayout}. It should not be
+ * called directly.
*/
OO.ui.InputWidget.prototype.simulateLabelClick = function () {
if ( !this.isDisabled() ) {
- if ( this.$input.is( ':checkbox,:radio' ) ) {
+ if ( this.$input.is( ':checkbox, :radio' ) ) {
this.$input.click();
- } else if ( this.$input.is( ':input' ) ) {
- this.$input[0].focus();
+ }
+ if ( this.$input.is( ':input' ) ) {
+ this.$input[ 0 ].focus();
}
}
};
/**
- * Check if the widget is read-only.
- *
- * @return {boolean}
+ * @inheritdoc
*/
-OO.ui.InputWidget.prototype.isReadOnly = function () {
- return this.readOnly;
+OO.ui.InputWidget.prototype.setDisabled = function ( state ) {
+ OO.ui.InputWidget.super.prototype.setDisabled.call( this, state );
+ if ( this.$input ) {
+ this.$input.prop( 'disabled', this.isDisabled() );
+ }
+ return this;
};
/**
- * Set the read-only state of the widget.
+ * Focus the input.
*
- * This should probably change the widgets's appearance and prevent it from being used.
+ * @chainable
+ */
+OO.ui.InputWidget.prototype.focus = function () {
+ this.$input[ 0 ].focus();
+ return this;
+};
+
+/**
+ * Blur the input.
*
- * @param {boolean} state Make input read-only
* @chainable
*/
-OO.ui.InputWidget.prototype.setReadOnly = function ( state ) {
- this.readOnly = !!state;
- this.$input.prop( 'readOnly', this.readOnly );
+OO.ui.InputWidget.prototype.blur = function () {
+ this.$input[ 0 ].blur();
return this;
};
/**
- * @inheritdoc
+ * ButtonInputWidget is used to submit HTML forms and is intended to be used within
+ * a OO.ui.FormLayout. If you do not need the button to work with HTML forms, you probably
+ * want to use OO.ui.ButtonWidget instead. Button input widgets can be rendered as either an
+ * HTML `<button/>` (the default) or an HTML `<input/>` tags. See the
+ * [OOjs UI documentation on MediaWiki] [1] for more information.
+ *
+ * @example
+ * // A ButtonInputWidget rendered as an HTML button, the default.
+ * var button = new OO.ui.ButtonInputWidget( {
+ * label: 'Input button',
+ * icon: 'check',
+ * value: 'check'
+ * } );
+ * $( 'body' ).append( button.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs#Button_inputs
+ *
+ * @class
+ * @extends OO.ui.InputWidget
+ * @mixins OO.ui.ButtonElement
+ * @mixins OO.ui.IconElement
+ * @mixins OO.ui.IndicatorElement
+ * @mixins OO.ui.LabelElement
+ * @mixins OO.ui.TitledElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [type='button'] The value of the HTML `'type'` attribute: 'button', 'submit' or 'reset'.
+ * @cfg {boolean} [useInputTag=false] Use an `<input/>` tag instead of a `<button/>` tag, the default.
+ * Widgets configured to be an `<input/>` do not support {@link #icon icons} and {@link #indicator indicators},
+ * non-plaintext {@link #label labels}, or {@link #value values}. In general, useInputTag should only
+ * be set to `true` when there’s need to support IE6 in a form with multiple buttons.
*/
-OO.ui.InputWidget.prototype.setDisabled = function ( state ) {
- OO.ui.InputWidget.super.prototype.setDisabled.call( this, state );
- if ( this.$input ) {
- this.$input.prop( 'disabled', this.isDisabled() );
+OO.ui.ButtonInputWidget = function OoUiButtonInputWidget( config ) {
+ // Configuration initialization
+ config = $.extend( { type: 'button', useInputTag: false }, config );
+
+ // Properties (must be set before parent constructor, which calls #setValue)
+ this.useInputTag = config.useInputTag;
+
+ // Parent constructor
+ OO.ui.ButtonInputWidget.super.call( this, config );
+
+ // Mixin constructors
+ OO.ui.ButtonElement.call( this, $.extend( {}, config, { $button: this.$input } ) );
+ OO.ui.IconElement.call( this, config );
+ OO.ui.IndicatorElement.call( this, config );
+ OO.ui.LabelElement.call( this, config );
+ OO.ui.TitledElement.call( this, $.extend( {}, config, { $titled: this.$input } ) );
+
+ // Initialization
+ if ( !config.useInputTag ) {
+ this.$input.append( this.$icon, this.$label, this.$indicator );
}
- return this;
+ this.$element.addClass( 'oo-ui-buttonInputWidget' );
};
+/* Setup */
+
+OO.inheritClass( OO.ui.ButtonInputWidget, OO.ui.InputWidget );
+OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.ButtonElement );
+OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.IconElement );
+OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.IndicatorElement );
+OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.LabelElement );
+OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.TitledElement );
+
+/* Methods */
+
/**
- * Focus the input.
+ * @inheritdoc
+ * @private
+ */
+OO.ui.ButtonInputWidget.prototype.getInputElement = function ( config ) {
+ var html = '<' + ( config.useInputTag ? 'input' : 'button' ) + ' type="' + config.type + '">';
+ return $( html );
+};
+
+/**
+ * Set label value.
+ *
+ * If #useInputTag is `true`, the label is set as the `value` of the `<input/>` tag.
*
+ * @param {jQuery|string|Function|null} label Label nodes, text, a function that returns nodes or
+ * text, or `null` for no label
* @chainable
*/
-OO.ui.InputWidget.prototype.focus = function () {
- this.$input[0].focus();
+OO.ui.ButtonInputWidget.prototype.setLabel = function ( label ) {
+ OO.ui.LabelElement.prototype.setLabel.call( this, label );
+
+ if ( this.useInputTag ) {
+ if ( typeof label === 'function' ) {
+ label = OO.ui.resolveMsg( label );
+ }
+ if ( label instanceof jQuery ) {
+ label = label.text();
+ }
+ if ( !label ) {
+ label = '';
+ }
+ this.$input.val( label );
+ }
+
return this;
};
/**
- * Blur the input.
+ * Set the value of the input.
+ *
+ * This method is disabled for button inputs configured as {@link #useInputTag <input/> tags}, as
+ * they do not support {@link #value values}.
*
+ * @param {string} value New value
* @chainable
*/
-OO.ui.InputWidget.prototype.blur = function () {
- this.$input[0].blur();
+OO.ui.ButtonInputWidget.prototype.setValue = function ( value ) {
+ if ( !this.useInputTag ) {
+ OO.ui.ButtonInputWidget.super.prototype.setValue.call( this, value );
+ }
return this;
};
/**
- * Checkbox input widget.
+ * CheckboxInputWidgets, like HTML checkboxes, can be selected and/or configured with a value.
+ * Note that these {@link OO.ui.InputWidget input widgets} are best laid out
+ * in {@link OO.ui.FieldLayout field layouts} that use the {@link OO.ui.FieldLayout#align inline}
+ * alignment. For more information, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
+ *
+ * @example
+ * // An example of selected, unselected, and disabled checkbox inputs
+ * var checkbox1=new OO.ui.CheckboxInputWidget( {
+ * value: 'a',
+ * selected: true
+ * } );
+ * var checkbox2=new OO.ui.CheckboxInputWidget( {
+ * value: 'b'
+ * } );
+ * var checkbox3=new OO.ui.CheckboxInputWidget( {
+ * value:'c',
+ * disabled: true
+ * } );
+ * // Create a fieldset layout with fields for each checkbox.
+ * var fieldset = new OO.ui.FieldsetLayout( {
+ * label: 'Checkboxes'
+ * } );
+ * fieldset.addItems( [
+ * new OO.ui.FieldLayout( checkbox1, { label: 'Selected checkbox', align: 'inline' } ),
+ * new OO.ui.FieldLayout( checkbox2, { label: 'Unselected checkbox', align: 'inline' } ),
+ * new OO.ui.FieldLayout( checkbox3, { label: 'Disabled checkbox', align: 'inline' } ),
+ * ] );
+ * $( 'body' ).append( fieldset.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
*
* @class
* @extends OO.ui.InputWidget
*
* @constructor
* @param {Object} [config] Configuration options
+ * @cfg {boolean} [selected=false] Select the checkbox initially. By default, the checkbox is not selected.
*/
OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
// Parent constructor
OO.ui.CheckboxInputWidget.super.call( this, config );
// Initialization
this.$element.addClass( 'oo-ui-checkboxInputWidget' );
+ this.setSelected( config.selected !== undefined ? config.selected : false );
};
/* Setup */
OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );
-/* Events */
-
/* Methods */
/**
- * Get input element.
- *
- * @return {jQuery} Input element
+ * @inheritdoc
+ * @private
*/
OO.ui.CheckboxInputWidget.prototype.getInputElement = function () {
- return this.$( '<input type="checkbox" />' );
+ return $( '<input type="checkbox" />' );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
+ var widget = this;
+ if ( !this.isDisabled() ) {
+ // Allow the stack to clear so the value will be updated
+ setTimeout( function () {
+ widget.setSelected( widget.$input.prop( 'checked' ) );
+ } );
+ }
};
/**
- * Get checked state of the checkbox
+ * Set selection state of this checkbox.
*
- * @return {boolean} If the checkbox is checked
+ * @param {boolean} state `true` for selected
+ * @chainable
*/
-OO.ui.CheckboxInputWidget.prototype.getValue = function () {
- return this.value;
+OO.ui.CheckboxInputWidget.prototype.setSelected = function ( state ) {
+ state = !!state;
+ if ( this.selected !== state ) {
+ this.selected = state;
+ this.$input.prop( 'checked', this.selected );
+ this.emit( 'change', this.selected );
+ }
+ return this;
};
/**
- * Set value
+ * Check if this checkbox is selected.
+ *
+ * @return {boolean} Checkbox is selected
*/
-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 );
+OO.ui.CheckboxInputWidget.prototype.isSelected = function () {
+ // Resynchronize our internal data with DOM data. Other scripts executing on the page can modify
+ // it, and we won't know unless they're kind enough to trigger a 'change' event.
+ var selected = this.$input.prop( 'checked' );
+ if ( this.selected !== selected ) {
+ this.setSelected( selected );
}
+ return this.selected;
};
/**
+ * DropdownInputWidget is a {@link OO.ui.DropdownWidget DropdownWidget} intended to be used
+ * within a HTML form, such as a OO.ui.FormLayout. The selected value is synchronized with the value
+ * of a hidden HTML `input` tag. Please see the [OOjs UI documentation on MediaWiki][1] for
+ * more information about input widgets.
+ *
+ * @example
+ * // Example: A DropdownInputWidget with three options
+ * var dropDown = new OO.ui.DropdownInputWidget( {
+ * label: 'Dropdown menu: Select a menu option',
+ * options: [
+ * { data: 'a', label: 'First' } ,
+ * { data: 'b', label: 'Second'} ,
+ * { data: 'c', label: 'Third' }
+ * ]
+ * } );
+ * $( 'body' ).append( dropDown.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
+ *
+ * @class
+ * @extends OO.ui.InputWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`
+ */
+OO.ui.DropdownInputWidget = function OoUiDropdownInputWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Properties (must be done before parent constructor which calls #setDisabled)
+ this.dropdownWidget = new OO.ui.DropdownWidget();
+
+ // Parent constructor
+ OO.ui.DropdownInputWidget.super.call( this, config );
+
+ // Events
+ this.dropdownWidget.getMenu().connect( this, { select: 'onMenuSelect' } );
+
+ // Initialization
+ this.setOptions( config.options || [] );
+ this.$element
+ .addClass( 'oo-ui-dropdownInputWidget' )
+ .append( this.dropdownWidget.$element );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.DropdownInputWidget, OO.ui.InputWidget );
+
+/* Methods */
+
+/**
* @inheritdoc
+ * @private
*/
-OO.ui.CheckboxInputWidget.prototype.onEdit = function () {
- var widget = this;
- if ( !this.isDisabled() ) {
- // Allow the stack to clear so the value will be updated
- setTimeout( function () {
- widget.setValue( widget.$input.prop( 'checked' ) );
- } );
+OO.ui.DropdownInputWidget.prototype.getInputElement = function () {
+ return $( '<input type="hidden">' );
+};
+
+/**
+ * Handles menu select events.
+ *
+ * @private
+ * @param {OO.ui.MenuOptionWidget} item Selected menu item
+ */
+OO.ui.DropdownInputWidget.prototype.onMenuSelect = function ( item ) {
+ this.setValue( item.getData() );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.DropdownInputWidget.prototype.setValue = function ( value ) {
+ this.dropdownWidget.getMenu().selectItemByData( value );
+ OO.ui.DropdownInputWidget.super.prototype.setValue.call( this, value );
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.DropdownInputWidget.prototype.setDisabled = function ( state ) {
+ this.dropdownWidget.setDisabled( state );
+ OO.ui.DropdownInputWidget.super.prototype.setDisabled.call( this, state );
+ return this;
+};
+
+/**
+ * Set the options available for this input.
+ *
+ * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`
+ * @chainable
+ */
+OO.ui.DropdownInputWidget.prototype.setOptions = function ( options ) {
+ var value = this.getValue();
+
+ // Rebuild the dropdown menu
+ this.dropdownWidget.getMenu()
+ .clearItems()
+ .addItems( options.map( function ( opt ) {
+ return new OO.ui.MenuOptionWidget( {
+ data: opt.data,
+ label: opt.label !== undefined ? opt.label : opt.data
+ } );
+ } ) );
+
+ // Restore the previous value, or reset to something sensible
+ if ( this.dropdownWidget.getMenu().getItemFromData( value ) ) {
+ // Previous value is still available, ensure consistency with the dropdown
+ this.setValue( value );
+ } else {
+ // No longer valid, reset
+ if ( options.length ) {
+ this.setValue( options[ 0 ].data );
+ }
}
+
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.DropdownInputWidget.prototype.focus = function () {
+ this.dropdownWidget.getMenu().toggle( true );
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.DropdownInputWidget.prototype.blur = function () {
+ this.dropdownWidget.getMenu().toggle( false );
+ return this;
+};
+
+/**
+ * RadioInputWidget creates a single radio button. Because radio buttons are usually used as a set,
+ * in most cases you will want to use a {@link OO.ui.RadioSelectWidget radio select}
+ * with {@link OO.ui.RadioOptionWidget radio options} instead of this class. For more information,
+ * please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
+ *
+ * @example
+ * // An example of selected, unselected, and disabled radio inputs
+ * var radio1 = new OO.ui.RadioInputWidget( {
+ * value: 'a',
+ * selected: true
+ * } );
+ * var radio2 = new OO.ui.RadioInputWidget( {
+ * value: 'b'
+ * } );
+ * var radio3 = new OO.ui.RadioInputWidget( {
+ * value: 'c',
+ * disabled: true
+ * } );
+ * // Create a fieldset layout with fields for each radio button.
+ * var fieldset = new OO.ui.FieldsetLayout( {
+ * label: 'Radio inputs'
+ * } );
+ * fieldset.addItems( [
+ * new OO.ui.FieldLayout( radio1, { label: 'Selected', align: 'inline' } ),
+ * new OO.ui.FieldLayout( radio2, { label: 'Unselected', align: 'inline' } ),
+ * new OO.ui.FieldLayout( radio3, { label: 'Disabled', align: 'inline' } ),
+ * ] );
+ * $( 'body' ).append( fieldset.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
+ *
+ * @class
+ * @extends OO.ui.InputWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [selected=false] Select the radio button initially. By default, the radio button is not selected.
+ */
+OO.ui.RadioInputWidget = function OoUiRadioInputWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.RadioInputWidget.super.call( this, config );
+
+ // Initialization
+ this.$element.addClass( 'oo-ui-radioInputWidget' );
+ this.setSelected( config.selected !== undefined ? config.selected : false );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.RadioInputWidget, OO.ui.InputWidget );
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ * @private
+ */
+OO.ui.RadioInputWidget.prototype.getInputElement = function () {
+ return $( '<input type="radio" />' );
};
/**
- * Input widget with a text field.
+ * @inheritdoc
+ */
+OO.ui.RadioInputWidget.prototype.onEdit = function () {
+ // RadioInputWidget doesn't track its state.
+};
+
+/**
+ * Set selection state of this radio button.
+ *
+ * @param {boolean} state `true` for selected
+ * @chainable
+ */
+OO.ui.RadioInputWidget.prototype.setSelected = function ( state ) {
+ // RadioInputWidget doesn't track its state.
+ this.$input.prop( 'checked', state );
+ return this;
+};
+
+/**
+ * Check if this radio button is selected.
+ *
+ * @return {boolean} Radio is selected
+ */
+OO.ui.RadioInputWidget.prototype.isSelected = function () {
+ return this.$input.prop( 'checked' );
+};
+
+/**
+ * TextInputWidgets, like HTML text inputs, can be configured with options that customize the
+ * size of the field as well as its presentation. In addition, these widgets can be configured
+ * with {@link OO.ui.IconElement icons}, {@link OO.ui.IndicatorElement indicators}, an optional
+ * validation-pattern (used to determine if an input value is valid or not) and an input filter,
+ * which modifies incoming values rather than validating them.
+ * Please see the [OOjs UI documentation on MediaWiki] [1] for more information and examples.
+ *
+ * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
+ *
+ * @example
+ * // Example of a text input widget
+ * var textInput = new OO.ui.TextInputWidget( {
+ * value: 'Text input'
+ * } )
+ * $( 'body' ).append( textInput.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
*
* @class
* @extends OO.ui.InputWidget
* @mixins OO.ui.IconElement
* @mixins OO.ui.IndicatorElement
* @mixins OO.ui.PendingElement
+ * @mixins OO.ui.LabelElement
*
* @constructor
* @param {Object} [config] Configuration options
+ * @cfg {string} [type='text'] The value of the HTML `type` attribute
* @cfg {string} [placeholder] Placeholder text
+ * @cfg {boolean} [autofocus=false] Use an HTML `autofocus` attribute to
+ * instruct the browser to focus this widget.
+ * @cfg {boolean} [readOnly=false] Prevent changes to the value of the text input.
+ * @cfg {number} [maxLength] Maximum number of characters allowed in the input.
* @cfg {boolean} [multiline=false] Allow multiple lines of text
- * @cfg {boolean} [autosize=false] Automatically resize to fit content
- * @cfg {boolean} [maxRows=10] Maximum number of rows to make visible when autosizing
+ * @cfg {boolean} [autosize=false] Automatically resize the text input to fit its content.
+ * Use the #maxRows config to specify a maximum number of displayed rows.
+ * @cfg {boolean} [maxRows=10] Maximum number of rows to display when #autosize is set to true.
+ * @cfg {string} [labelPosition='after'] The position of the inline label relative to that of
+ * the value or placeholder text: `'before'` or `'after'`
+ * @cfg {boolean} [required=false] Mark the field as required
+ * @cfg {RegExp|Function|string} [validate] Validation pattern: when string, a symbolic name of a
+ * pattern defined by the class: 'non-empty' (the value cannot be an empty string) or 'integer'
+ * (the value must contain only numbers); when RegExp, a regular expression that must match the
+ * value for it to be considered valid; when Function, a function receiving the value as parameter
+ * that must return true, or promise resolving to true, for it to be considered valid.
*/
OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
// Configuration initialization
- config = config || {};
+ config = $.extend( {
+ type: 'text',
+ labelPosition: 'after',
+ maxRows: 10
+ }, config );
// Parent constructor
OO.ui.TextInputWidget.super.call( this, config );
@@ -8957,26 +12798,61 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
OO.ui.IconElement.call( this, config );
OO.ui.IndicatorElement.call( this, config );
OO.ui.PendingElement.call( this, config );
+ OO.ui.LabelElement.call( this, config );
// Properties
+ this.readOnly = false;
this.multiline = !!config.multiline;
this.autosize = !!config.autosize;
- this.maxRows = config.maxRows !== undefined ? config.maxRows : 10;
+ this.maxRows = config.maxRows;
+ this.validate = null;
+
+ // Clone for resizing
+ if ( this.autosize ) {
+ this.$clone = this.$input
+ .clone()
+ .insertAfter( this.$input )
+ .attr( 'aria-hidden', 'true' )
+ .addClass( 'oo-ui-element-hidden' );
+ }
+
+ this.setValidation( config.validate );
+ this.setLabelPosition( config.labelPosition );
// Events
- this.$input.on( 'keypress', OO.ui.bind( this.onKeyPress, this ) );
- this.$element.on( 'DOMNodeInsertedIntoDocument', OO.ui.bind( this.onElementAttach, this ) );
- this.$icon.on( 'mousedown', OO.ui.bind( this.onIconMouseDown, this ) );
- this.$indicator.on( 'mousedown', OO.ui.bind( this.onIndicatorMouseDown, this ) );
+ this.$input.on( {
+ keypress: this.onKeyPress.bind( this ),
+ blur: this.onBlur.bind( this )
+ } );
+ this.$input.one( {
+ focus: this.onElementAttach.bind( this )
+ } );
+ this.$icon.on( 'mousedown', this.onIconMouseDown.bind( this ) );
+ this.$indicator.on( 'mousedown', this.onIndicatorMouseDown.bind( this ) );
+ this.on( 'labelChange', this.updatePosition.bind( this ) );
+ this.connect( this, { change: 'onChange' } );
// Initialization
this.$element
.addClass( 'oo-ui-textInputWidget' )
.append( this.$icon, this.$indicator );
+ this.setReadOnly( !!config.readOnly );
if ( config.placeholder ) {
this.$input.attr( 'placeholder', config.placeholder );
}
- this.$element.attr( 'role', 'textbox' );
+ if ( config.maxLength !== undefined ) {
+ this.$input.attr( 'maxlength', config.maxLength );
+ }
+ if ( config.autofocus ) {
+ this.$input.attr( 'autofocus', 'autofocus' );
+ }
+ if ( config.required ) {
+ this.$input.attr( 'required', 'required' );
+ this.$input.attr( 'aria-required', 'true' );
+ }
+ if ( this.label || config.autosize ) {
+ this.installParentChangeDetector();
+ }
};
/* Setup */
@@ -8985,41 +12861,37 @@ OO.inheritClass( OO.ui.TextInputWidget, OO.ui.InputWidget );
OO.mixinClass( OO.ui.TextInputWidget, OO.ui.IconElement );
OO.mixinClass( OO.ui.TextInputWidget, OO.ui.IndicatorElement );
OO.mixinClass( OO.ui.TextInputWidget, OO.ui.PendingElement );
+OO.mixinClass( OO.ui.TextInputWidget, OO.ui.LabelElement );
+
+/* Static properties */
+
+OO.ui.TextInputWidget.static.validationPatterns = {
+ 'non-empty': /.+/,
+ integer: /^\d+$/
+};
/* Events */
/**
- * User presses enter inside the text box.
+ * An `enter` event is emitted when the user presses 'enter' inside the text box.
*
- * Not called if input is multiline.
+ * Not emitted if the input is multiline.
*
* @event enter
*/
-/**
- * User clicks the icon.
- *
- * @event icon
- */
-
-/**
- * User clicks the indicator.
- *
- * @event indicator
- */
-
/* Methods */
/**
* Handle icon mouse down events.
*
+ * @private
* @param {jQuery.Event} e Mouse down event
* @fires icon
*/
OO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {
if ( e.which === 1 ) {
- this.$input[0].focus();
- this.emit( 'icon' );
+ this.$input[ 0 ].focus();
return false;
}
};
@@ -9027,13 +12899,13 @@ OO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {
/**
* Handle indicator mouse down events.
*
+ * @private
* @param {jQuery.Event} e Mouse down event
* @fires indicator
*/
OO.ui.TextInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
if ( e.which === 1 ) {
- this.$input[0].focus();
- this.emit( 'indicator' );
+ this.$input[ 0 ].focus();
return false;
}
};
@@ -9041,96 +12913,203 @@ OO.ui.TextInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
/**
* Handle key press events.
*
+ * @private
* @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' );
+ this.emit( 'enter', e );
}
};
/**
+ * Handle blur events.
+ *
+ * @private
+ * @param {jQuery.Event} e Blur event
+ */
+OO.ui.TextInputWidget.prototype.onBlur = function () {
+ this.setValidityFlag();
+};
+
+/**
* Handle element attach events.
*
+ * @private
* @param {jQuery.Event} e Element attach event
*/
OO.ui.TextInputWidget.prototype.onElementAttach = function () {
+ // Any previously calculated size is now probably invalid if we reattached elsewhere
+ this.valCache = null;
this.adjustSize();
+ this.positionLabel();
};
/**
- * @inheritdoc
+ * Handle change events.
+ *
+ * @param {string} value
+ * @private
*/
-OO.ui.TextInputWidget.prototype.onEdit = function () {
+OO.ui.TextInputWidget.prototype.onChange = function () {
+ this.setValidityFlag();
this.adjustSize();
-
- // Parent method
- return OO.ui.TextInputWidget.super.prototype.onEdit.call( this );
};
/**
- * @inheritdoc
+ * Check if the input is {@link #readOnly read-only}.
+ *
+ * @return {boolean}
*/
-OO.ui.TextInputWidget.prototype.setValue = function ( value ) {
- // Parent method
- OO.ui.TextInputWidget.super.prototype.setValue.call( this, value );
+OO.ui.TextInputWidget.prototype.isReadOnly = function () {
+ return this.readOnly;
+};
- this.adjustSize();
+/**
+ * Set the {@link #readOnly read-only} state of the input.
+ *
+ * @param {boolean} state Make input read-only
+ * @chainable
+ */
+OO.ui.TextInputWidget.prototype.setReadOnly = function ( state ) {
+ this.readOnly = !!state;
+ this.$input.prop( 'readOnly', this.readOnly );
return this;
};
/**
+ * Support function for making #onElementAttach work across browsers.
+ *
+ * This whole function could be replaced with one line of code using the DOMNodeInsertedIntoDocument
+ * event, but it's not supported by Firefox and allegedly deprecated, so we only use it as fallback.
+ *
+ * Due to MutationObserver performance woes, #onElementAttach is only somewhat reliably called the
+ * first time that the element gets attached to the documented.
+ */
+OO.ui.TextInputWidget.prototype.installParentChangeDetector = function () {
+ var mutationObserver, onRemove, topmostNode, fakeParentNode,
+ MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver,
+ widget = this;
+
+ if ( MutationObserver ) {
+ // The new way. If only it wasn't so ugly.
+
+ if ( this.$element.closest( 'html' ).length ) {
+ // Widget is attached already, do nothing. This breaks the functionality of this function when
+ // the widget is detached and reattached. Alas, doing this correctly with MutationObserver
+ // would require observation of the whole document, which would hurt performance of other,
+ // more important code.
+ return;
+ }
+
+ // Find topmost node in the tree
+ topmostNode = this.$element[0];
+ while ( topmostNode.parentNode ) {
+ topmostNode = topmostNode.parentNode;
+ }
+
+ // We have no way to detect the $element being attached somewhere without observing the entire
+ // DOM with subtree modifications, which would hurt performance. So we cheat: we hook to the
+ // parent node of $element, and instead detect when $element is removed from it (and thus
+ // probably attached somewhere else). If there is no parent, we create a "fake" one. If it
+ // doesn't get attached, we end up back here and create the parent.
+
+ mutationObserver = new MutationObserver( function ( mutations ) {
+ var i, j, removedNodes;
+ for ( i = 0; i < mutations.length; i++ ) {
+ removedNodes = mutations[ i ].removedNodes;
+ for ( j = 0; j < removedNodes.length; j++ ) {
+ if ( removedNodes[ j ] === topmostNode ) {
+ setTimeout( onRemove, 0 );
+ return;
+ }
+ }
+ }
+ } );
+
+ onRemove = function () {
+ // If the node was attached somewhere else, report it
+ if ( widget.$element.closest( 'html' ).length ) {
+ widget.onElementAttach();
+ }
+ mutationObserver.disconnect();
+ widget.installParentChangeDetector();
+ };
+
+ // Create a fake parent and observe it
+ fakeParentNode = $( '<div>' ).append( this.$element )[0];
+ mutationObserver.observe( fakeParentNode, { childList: true } );
+ } else {
+ // Using the DOMNodeInsertedIntoDocument event is much nicer and less magical, and works for
+ // detachment and reattachment, but it's not supported by Firefox and allegedly deprecated.
+ this.$element.on( 'DOMNodeInsertedIntoDocument', this.onElementAttach.bind( this ) );
+ }
+};
+
+/**
* Automatically adjust the size of the text input.
*
- * This only affects multi-line inputs that are auto-sized.
+ * This only affects #multiline inputs that are {@link #autosize autosized}.
*
* @chainable
*/
OO.ui.TextInputWidget.prototype.adjustSize = function () {
- var $clone, scrollHeight, innerHeight, outerHeight, maxInnerHeight, idealHeight;
+ var scrollHeight, innerHeight, outerHeight, maxInnerHeight, measurementError, idealHeight;
- if ( this.multiline && this.autosize ) {
- $clone = this.$input.clone()
+ if ( this.multiline && this.autosize && this.$input.val() !== this.valCache ) {
+ this.$clone
.val( this.$input.val() )
- .css( { height: 0 } )
- .insertAfter( this.$input );
- // Set inline height property to 0 to measure scroll height
- scrollHeight = $clone[0].scrollHeight;
+ .attr( 'rows', '' )
+ // Set inline height property to 0 to measure scroll height
+ .css( 'height', 0 );
+
+ this.$clone.removeClass( 'oo-ui-element-hidden' );
+
+ this.valCache = this.$input.val();
+
+ scrollHeight = this.$clone[ 0 ].scrollHeight;
+
// Remove inline height property to measure natural heights
- $clone.css( 'height', '' );
- innerHeight = $clone.innerHeight();
- outerHeight = $clone.outerHeight();
+ this.$clone.css( 'height', '' );
+ innerHeight = this.$clone.innerHeight();
+ outerHeight = this.$clone.outerHeight();
+
// Measure max rows height
- $clone.attr( 'rows', this.maxRows ).css( 'height', 'auto' );
- maxInnerHeight = $clone.innerHeight();
- $clone.removeAttr( 'rows' ).css( 'height', '' );
- $clone.remove();
- idealHeight = Math.min( maxInnerHeight, scrollHeight );
+ this.$clone
+ .attr( 'rows', this.maxRows )
+ .css( 'height', 'auto' )
+ .val( '' );
+ maxInnerHeight = this.$clone.innerHeight();
+
+ // Difference between reported innerHeight and scrollHeight with no scrollbars present
+ // Equals 1 on Blink-based browsers and 0 everywhere else
+ measurementError = maxInnerHeight - this.$clone[ 0 ].scrollHeight;
+ idealHeight = Math.min( maxInnerHeight, scrollHeight + measurementError );
+
+ this.$clone.addClass( 'oo-ui-element-hidden' );
+
// Only apply inline height when expansion beyond natural height is needed
- this.$input.css(
- 'height',
+ if ( idealHeight > innerHeight ) {
// Use the difference between the inner and outer height as a buffer
- idealHeight > outerHeight ? idealHeight + ( outerHeight - innerHeight ) : ''
- );
+ this.$input.css( 'height', idealHeight + ( outerHeight - innerHeight ) );
+ } else {
+ this.$input.css( 'height', '' );
+ }
}
return this;
};
/**
- * Get input element.
- *
- * @param {Object} [config] Configuration options
- * @return {jQuery} Input element
+ * @inheritdoc
+ * @private
*/
OO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {
- return config.multiline ? this.$( '<textarea>' ) : this.$( '<input type="text" />' );
+ return config.multiline ? $( '<textarea>' ) : $( '<input type="' + config.type + '" />' );
};
-/* Methods */
-
/**
- * Check if input supports multiple lines.
+ * Check if the input supports multiple lines.
*
* @return {boolean}
*/
@@ -9139,7 +13118,7 @@ OO.ui.TextInputWidget.prototype.isMultiline = function () {
};
/**
- * Check if input automatically adjusts its size.
+ * Check if the input automatically adjusts its size.
*
* @return {boolean}
*/
@@ -9148,7 +13127,7 @@ OO.ui.TextInputWidget.prototype.isAutosizing = function () {
};
/**
- * Select the contents of the input.
+ * Select the entire text of the input.
*
* @chainable
*/
@@ -9158,15 +13137,198 @@ OO.ui.TextInputWidget.prototype.select = function () {
};
/**
- * Text input with a menu of optional values.
+ * Set the validation pattern.
+ *
+ * The validation pattern is either a regular expression, a function, or the symbolic name of a
+ * pattern defined by the class: 'non-empty' (the value cannot be an empty string) or 'integer' (the
+ * value must contain only numbers).
+ *
+ * @param {RegExp|Function|string|null} validate Regular expression, function, or the symbolic name
+ * of a pattern (either ‘integer’ or ‘non-empty’) defined by the class.
+ */
+OO.ui.TextInputWidget.prototype.setValidation = function ( validate ) {
+ if ( validate instanceof RegExp || validate instanceof Function ) {
+ this.validate = validate;
+ } else {
+ this.validate = this.constructor.static.validationPatterns[ validate ] || /.*/;
+ }
+};
+
+/**
+ * Sets the 'invalid' flag appropriately.
+ *
+ * @param {boolean} [isValid] Optionally override validation result
+ */
+OO.ui.TextInputWidget.prototype.setValidityFlag = function ( isValid ) {
+ var widget = this,
+ setFlag = function ( valid ) {
+ if ( !valid ) {
+ widget.$input.attr( 'aria-invalid', 'true' );
+ } else {
+ widget.$input.removeAttr( 'aria-invalid' );
+ }
+ widget.setFlags( { invalid: !valid } );
+ };
+
+ if ( isValid !== undefined ) {
+ setFlag( isValid );
+ } else {
+ this.isValid().done( setFlag );
+ }
+};
+
+/**
+ * Check if a value is valid.
+ *
+ * This method returns a promise that resolves with a boolean `true` if the current value is
+ * considered valid according to the supplied {@link #validate validation pattern}.
+ *
+ * @return {jQuery.Promise} A promise that resolves to a boolean `true` if the value is valid.
+ */
+OO.ui.TextInputWidget.prototype.isValid = function () {
+ if ( this.validate instanceof Function ) {
+ var result = this.validate( this.getValue() );
+ if ( $.isFunction( result.promise ) ) {
+ return result.promise();
+ } else {
+ return $.Deferred().resolve( !!result ).promise();
+ }
+ } else {
+ return $.Deferred().resolve( !!this.getValue().match( this.validate ) ).promise();
+ }
+};
+
+/**
+ * Set the position of the inline label relative to that of the value: `‘before’` or `‘after’`.
+ *
+ * @param {string} labelPosition Label position, 'before' or 'after'
+ * @chainable
+ */
+OO.ui.TextInputWidget.prototype.setLabelPosition = function ( labelPosition ) {
+ this.labelPosition = labelPosition;
+ this.updatePosition();
+ return this;
+};
+
+/**
+ * Deprecated alias of #setLabelPosition
+ *
+ * @deprecated Use setLabelPosition instead.
+ */
+OO.ui.TextInputWidget.prototype.setPosition =
+ OO.ui.TextInputWidget.prototype.setLabelPosition;
+
+/**
+ * Update the position of the inline label.
+ *
+ * This method is called by #setLabelPosition, and can also be called on its own if
+ * something causes the label to be mispositioned.
+ *
+ *
+ * @chainable
+ */
+OO.ui.TextInputWidget.prototype.updatePosition = function () {
+ var after = this.labelPosition === 'after';
+
+ this.$element
+ .toggleClass( 'oo-ui-textInputWidget-labelPosition-after', !!this.label && after )
+ .toggleClass( 'oo-ui-textInputWidget-labelPosition-before', !!this.label && !after );
+
+ if ( this.label ) {
+ this.positionLabel();
+ }
+
+ return this;
+};
+
+/**
+ * Position the label by setting the correct padding on the input.
+ *
+ * @private
+ * @chainable
+ */
+OO.ui.TextInputWidget.prototype.positionLabel = function () {
+ // Clear old values
+ this.$input
+ // Clear old values if present
+ .css( {
+ 'padding-right': '',
+ 'padding-left': ''
+ } );
+
+ if ( this.label ) {
+ this.$element.append( this.$label );
+ } else {
+ this.$label.detach();
+ return;
+ }
+
+ var after = this.labelPosition === 'after',
+ rtl = this.$element.css( 'direction' ) === 'rtl',
+ property = after === rtl ? 'padding-left' : 'padding-right';
+
+ this.$input.css( property, this.$label.outerWidth( true ) );
+
+ return this;
+};
+
+/**
+ * ComboBoxWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value
+ * can be entered manually) and a {@link OO.ui.MenuSelectWidget menu of options} (from which
+ * a value can be chosen instead). Users can choose options from the combo box in one of two ways:
+ *
+ * - by typing a value in the text input field. If the value exactly matches the value of a menu
+ * option, that option will appear to be selected.
+ * - by choosing a value from the menu. The value of the chosen option will then appear in the text
+ * input field.
+ *
+ * For more information about menus and options, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * @example
+ * // Example: A ComboBoxWidget.
+ * var comboBox = new OO.ui.ComboBoxWidget( {
+ * label: 'ComboBoxWidget',
+ * input: { value: 'Option One' },
+ * menu: {
+ * items: [
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'Option 1',
+ * label: 'Option One'
+ * } ),
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'Option 2',
+ * label: 'Option Two'
+ * } ),
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'Option 3',
+ * label: 'Option Three'
+ * } ),
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'Option 4',
+ * label: 'Option Four'
+ * } ),
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'Option 5',
+ * label: 'Option Five'
+ * } )
+ * ]
+ * }
+ * } );
+ * $( 'body' ).append( comboBox.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
*
* @class
* @extends OO.ui.Widget
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {Object} [menu] Configuration options to pass to menu widget
- * @cfg {Object} [input] Configuration options to pass to input widget
+ * @cfg {Object} [menu] Configuration options to pass to the {@link OO.ui.MenuSelectWidget menu select widget}.
+ * @cfg {Object} [input] Configuration options to pass to the {@link OO.ui.TextInputWidget text input widget}.
+ * @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful in cases where
+ * the expanded menu is larger than its containing `<div>`. The specified overlay layer is usually on top of the
+ * containing `<div>` and has a larger area. By default, the menu uses relative positioning.
*/
OO.ui.ComboBoxWidget = function OoUiComboBoxWidget( config ) {
// Configuration initialization
@@ -9175,20 +13337,42 @@ OO.ui.ComboBoxWidget = function OoUiComboBoxWidget( config ) {
// Parent constructor
OO.ui.ComboBoxWidget.super.call( this, config );
+ // Properties (must be set before TabIndexedElement constructor call)
+ this.$indicator = this.$( '<span>' );
+
+ // Mixin constructors
+ OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$indicator } ) );
+
// Properties
+ this.$overlay = config.$overlay || this.$element;
this.input = new OO.ui.TextInputWidget( $.extend(
- { $: this.$, indicator: 'down', disabled: this.isDisabled() },
+ {
+ indicator: 'down',
+ $indicator: this.$indicator,
+ disabled: this.isDisabled()
+ },
config.input
) );
- this.menu = new OO.ui.MenuWidget( $.extend(
- { $: this.$, widget: this, input: this.input, disabled: this.isDisabled() },
+ this.input.$input.eq( 0 ).attr( {
+ role: 'combobox',
+ 'aria-autocomplete': 'list'
+ } );
+ this.menu = new OO.ui.TextInputMenuSelectWidget( this.input, $.extend(
+ {
+ widget: this,
+ input: this.input,
+ disabled: this.isDisabled()
+ },
config.menu
) );
// Events
+ this.$indicator.on( {
+ click: this.onClick.bind( this ),
+ keypress: this.onKeyPress.bind( this )
+ } );
this.input.connect( this, {
change: 'onInputChange',
- indicator: 'onInputIndicator',
enter: 'onInputEnter'
} );
this.menu.connect( this, {
@@ -9198,28 +13382,39 @@ OO.ui.ComboBoxWidget = function OoUiComboBoxWidget( config ) {
} );
// Initialization
- this.$element.addClass( 'oo-ui-comboBoxWidget' ).append(
- this.input.$element,
- this.menu.$element
- );
+ this.$element.addClass( 'oo-ui-comboBoxWidget' ).append( this.input.$element );
+ this.$overlay.append( this.menu.$element );
this.onMenuItemsChange();
};
/* Setup */
OO.inheritClass( OO.ui.ComboBoxWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.ComboBoxWidget, OO.ui.TabIndexedElement );
/* Methods */
/**
+ * Get the combobox's menu.
+ * @return {OO.ui.TextInputMenuSelectWidget} Menu widget
+ */
+OO.ui.ComboBoxWidget.prototype.getMenu = function () {
+ return this.menu;
+};
+
+/**
* Handle input change events.
*
+ * @private
* @param {string} value New value
*/
OO.ui.ComboBoxWidget.prototype.onInputChange = function ( value ) {
var match = this.menu.getItemFromData( value );
this.menu.selectItem( match );
+ if ( this.menu.getHighlightedItem() ) {
+ this.menu.highlightItem( match );
+ }
if ( !this.isDisabled() ) {
this.menu.toggle( true );
@@ -9227,16 +13422,39 @@ OO.ui.ComboBoxWidget.prototype.onInputChange = function ( value ) {
};
/**
- * Handle input indicator events.
+ * Handle mouse click events.
+ *
+ *
+ * @private
+ * @param {jQuery.Event} e Mouse click event
*/
-OO.ui.ComboBoxWidget.prototype.onInputIndicator = function () {
- if ( !this.isDisabled() ) {
+OO.ui.ComboBoxWidget.prototype.onClick = function ( e ) {
+ if ( !this.isDisabled() && e.which === 1 ) {
+ this.menu.toggle();
+ this.input.$input[ 0 ].focus();
+ }
+ return false;
+};
+
+/**
+ * Handle key press events.
+ *
+ *
+ * @private
+ * @param {jQuery.Event} e Key press event
+ */
+OO.ui.ComboBoxWidget.prototype.onKeyPress = function ( e ) {
+ if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
this.menu.toggle();
+ this.input.$input[ 0 ].focus();
+ return false;
}
};
/**
* Handle input enter events.
+ *
+ * @private
*/
OO.ui.ComboBoxWidget.prototype.onInputEnter = function () {
if ( !this.isDisabled() ) {
@@ -9247,18 +13465,24 @@ OO.ui.ComboBoxWidget.prototype.onInputEnter = function () {
/**
* Handle menu choose events.
*
+ * @private
* @param {OO.ui.OptionWidget} item Chosen item
*/
OO.ui.ComboBoxWidget.prototype.onMenuChoose = function ( item ) {
- if ( item ) {
- this.input.setValue( item.getData() );
- }
+ this.input.setValue( item.getData() );
};
/**
* Handle menu item change events.
+ *
+ * @private
*/
OO.ui.ComboBoxWidget.prototype.onMenuItemsChange = function () {
+ var match = this.menu.getItemFromData( this.input.getValue() );
+ this.menu.selectItem( match );
+ if ( this.menu.getHighlightedItem() ) {
+ this.menu.highlightItem( match );
+ }
this.$element.toggleClass( 'oo-ui-comboBoxWidget-empty', this.menu.isEmpty() );
};
@@ -9280,7 +13504,34 @@ OO.ui.ComboBoxWidget.prototype.setDisabled = function ( disabled ) {
};
/**
- * Label widget.
+ * LabelWidgets help identify the function of interface elements. Each LabelWidget can
+ * be configured with a `label` option that is set to a string, a label node, or a function:
+ *
+ * - String: a plaintext string
+ * - jQuery selection: a jQuery selection, used for anything other than a plaintext label, e.g., a
+ * label that includes a link or special styling, such as a gray color or additional graphical elements.
+ * - Function: a function that will produce a string in the future. Functions are used
+ * in cases where the value of the label is not currently defined.
+ *
+ * In addition, the LabelWidget can be associated with an {@link OO.ui.InputWidget input widget}, which
+ * will come into focus when the label is clicked.
+ *
+ * @example
+ * // Examples of LabelWidgets
+ * var label1 = new OO.ui.LabelWidget( {
+ * label: 'plaintext label'
+ * } );
+ * var label2 = new OO.ui.LabelWidget( {
+ * label: $( '<a href="default.html">jQuery label</a>' )
+ * } );
+ * // Create a fieldset layout with fields for each example
+ * var fieldset = new OO.ui.FieldsetLayout();
+ * fieldset.addItems( [
+ * new OO.ui.FieldLayout( label1 ),
+ * new OO.ui.FieldLayout( label2 )
+ * ] );
+ * $( 'body' ).append( fieldset.$element );
+ *
*
* @class
* @extends OO.ui.Widget
@@ -9288,9 +13539,11 @@ OO.ui.ComboBoxWidget.prototype.setDisabled = function ( disabled ) {
*
* @constructor
* @param {Object} [config] Configuration options
+ * @cfg {OO.ui.InputWidget} [input] {@link OO.ui.InputWidget Input widget} that uses the label.
+ * Clicking the label will focus the specified input field.
*/
OO.ui.LabelWidget = function OoUiLabelWidget( config ) {
- // Config intialization
+ // Configuration initialization
config = config || {};
// Parent constructor
@@ -9298,13 +13551,14 @@ OO.ui.LabelWidget = function OoUiLabelWidget( config ) {
// Mixin constructors
OO.ui.LabelElement.call( this, $.extend( {}, config, { $label: this.$element } ) );
+ OO.ui.TitledElement.call( this, config );
// Properties
this.input = config.input;
// Events
if ( this.input instanceof OO.ui.InputWidget ) {
- this.$element.on( 'click', OO.ui.bind( this.onClick, this ) );
+ this.$element.on( 'click', this.onClick.bind( this ) );
}
// Initialization
@@ -9315,6 +13569,7 @@ OO.ui.LabelWidget = function OoUiLabelWidget( config ) {
OO.inheritClass( OO.ui.LabelWidget, OO.ui.Widget );
OO.mixinClass( OO.ui.LabelWidget, OO.ui.LabelElement );
+OO.mixinClass( OO.ui.LabelWidget, OO.ui.TitledElement );
/* Static Properties */
@@ -9325,6 +13580,7 @@ OO.ui.LabelWidget.static.tagName = 'span';
/**
* Handles label mouse click events.
*
+ * @private
* @param {jQuery.Event} e Mouse click event
*/
OO.ui.LabelWidget.prototype.onClick = function () {
@@ -9333,7 +13589,12 @@ OO.ui.LabelWidget.prototype.onClick = function () {
};
/**
- * Generic option widget for use with OO.ui.SelectWidget.
+ * OptionWidgets are special elements that can be selected and configured with data. The
+ * data is often unique for each option, but it does not have to be. OptionWidgets are used
+ * with OO.ui.SelectWidget to create a selection of mutually exclusive options. For more information
+ * and examples, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
*
* @class
* @extends OO.ui.Widget
@@ -9341,12 +13602,10 @@ OO.ui.LabelWidget.prototype.onClick = function () {
* @mixins OO.ui.FlaggedElement
*
* @constructor
- * @param {Mixed} data Option data
* @param {Object} [config] Configuration options
- * @cfg {string} [rel] Value for `rel` attribute in DOM, allowing per-option styling
*/
-OO.ui.OptionWidget = function OoUiOptionWidget( data, config ) {
- // Config intialization
+OO.ui.OptionWidget = function OoUiOptionWidget( config ) {
+ // Configuration initialization
config = config || {};
// Parent constructor
@@ -9358,7 +13617,6 @@ OO.ui.OptionWidget = function OoUiOptionWidget( data, config ) {
OO.ui.FlaggedElement.call( this, config );
// Properties
- this.data = data;
this.selected = false;
this.highlighted = false;
this.pressed = false;
@@ -9366,13 +13624,9 @@ OO.ui.OptionWidget = function OoUiOptionWidget( data, config ) {
// Initialization
this.$element
.data( 'oo-ui-optionWidget', this )
- .attr( 'rel', config.rel )
.attr( 'role', 'option' )
.addClass( 'oo-ui-optionWidget' )
.append( this.$label );
- this.$element
- .prepend( this.$icon )
- .append( this.$indicator );
};
/* Setup */
@@ -9395,7 +13649,7 @@ OO.ui.OptionWidget.static.scrollIntoViewOnSelect = false;
/* Methods */
/**
- * Check if option can be selected.
+ * Check if the option can be selected.
*
* @return {boolean} Item is selectable
*/
@@ -9404,7 +13658,9 @@ OO.ui.OptionWidget.prototype.isSelectable = function () {
};
/**
- * Check if option can be highlighted.
+ * Check if the option can be highlighted. A highlight indicates that the option
+ * may be selected when a user presses enter or clicks. Disabled items cannot
+ * be highlighted.
*
* @return {boolean} Item is highlightable
*/
@@ -9413,7 +13669,8 @@ OO.ui.OptionWidget.prototype.isHighlightable = function () {
};
/**
- * Check if option can be pressed.
+ * Check if the option can be pressed. The pressed state occurs when a user mouses
+ * down on an item, but has not yet let go of the mouse.
*
* @return {boolean} Item is pressable
*/
@@ -9422,7 +13679,7 @@ OO.ui.OptionWidget.prototype.isPressable = function () {
};
/**
- * Check if option is selected.
+ * Check if the option is selected.
*
* @return {boolean} Item is selected
*/
@@ -9431,7 +13688,8 @@ OO.ui.OptionWidget.prototype.isSelected = function () {
};
/**
- * Check if option is highlighted.
+ * Check if the option is highlighted. A highlight indicates that the
+ * item may be selected when a user presses enter or clicks.
*
* @return {boolean} Item is highlighted
*/
@@ -9440,7 +13698,9 @@ OO.ui.OptionWidget.prototype.isHighlighted = function () {
};
/**
- * Check if option is pressed.
+ * Check if the option is pressed. The pressed state occurs when a user mouses
+ * down on an item, but has not yet let go of the mouse. The item may appear
+ * selected, but it will not be selected until the user releases the mouse.
*
* @return {boolean} Item is pressed
*/
@@ -9449,7 +13709,9 @@ OO.ui.OptionWidget.prototype.isPressed = function () {
};
/**
- * Set selected state.
+ * Set the option’s selected state. In general, all modifications to the selection
+ * should be handled by the SelectWidget’s {@link OO.ui.SelectWidget#selectItem selectItem( [item] )}
+ * method instead of this method.
*
* @param {boolean} [state=false] Select option
* @chainable
@@ -9457,16 +13719,22 @@ OO.ui.OptionWidget.prototype.isPressed = function () {
OO.ui.OptionWidget.prototype.setSelected = function ( state ) {
if ( this.constructor.static.selectable ) {
this.selected = !!state;
- this.$element.toggleClass( 'oo-ui-optionWidget-selected', state );
+ this.$element
+ .toggleClass( 'oo-ui-optionWidget-selected', state )
+ .attr( 'aria-selected', state.toString() );
if ( state && this.constructor.static.scrollIntoViewOnSelect ) {
this.scrollElementIntoView();
}
+ this.updateThemeClasses();
}
return this;
};
/**
- * Set highlighted state.
+ * Set the option’s highlighted state. In general, all programmatic
+ * modifications to the highlight should be handled by the
+ * SelectWidget’s {@link OO.ui.SelectWidget#highlightItem highlightItem( [item] )}
+ * method instead of this method.
*
* @param {boolean} [state=false] Highlight option
* @chainable
@@ -9475,12 +13743,16 @@ OO.ui.OptionWidget.prototype.setHighlighted = function ( state ) {
if ( this.constructor.static.highlightable ) {
this.highlighted = !!state;
this.$element.toggleClass( 'oo-ui-optionWidget-highlighted', state );
+ this.updateThemeClasses();
}
return this;
};
/**
- * Set pressed state.
+ * Set the option’s pressed state. In general, all
+ * programmatic modifications to the pressed state should be handled by the
+ * SelectWidget’s {@link OO.ui.SelectWidget#pressItem pressItem( [item] )}
+ * method instead of this method.
*
* @param {boolean} [state=false] Press option
* @chainable
@@ -9489,53 +13761,37 @@ OO.ui.OptionWidget.prototype.setPressed = function ( state ) {
if ( this.constructor.static.pressable ) {
this.pressed = !!state;
this.$element.toggleClass( 'oo-ui-optionWidget-pressed', state );
+ this.updateThemeClasses();
}
return this;
};
/**
- * Make the option's highlight flash.
- *
- * While flashing, the visual style of the pressed state is removed if present.
- *
- * @return {jQuery.Promise} Promise resolved when flashing is done
- */
-OO.ui.OptionWidget.prototype.flash = function () {
- var widget = this,
- $element = this.$element,
- deferred = $.Deferred();
-
- if ( !this.isDisabled() && this.constructor.static.pressable ) {
- $element.removeClass( 'oo-ui-optionWidget-highlighted oo-ui-optionWidget-pressed' );
- setTimeout( function () {
- // Restore original classes
- $element
- .toggleClass( 'oo-ui-optionWidget-highlighted', widget.highlighted )
- .toggleClass( 'oo-ui-optionWidget-pressed', widget.pressed );
-
- setTimeout( function () {
- deferred.resolve();
- }, 100 );
-
- }, 100 );
- }
-
- return deferred.promise();
-};
-
-/**
- * Get option data.
- *
- * @return {Mixed} Option data
- */
-OO.ui.OptionWidget.prototype.getData = function () {
- return this.data;
-};
-
-/**
- * Option widget with an option icon and indicator.
- *
- * Use together with OO.ui.SelectWidget.
+ * DecoratedOptionWidgets are {@link OO.ui.OptionWidget options} that can be configured
+ * with an {@link OO.ui.IconElement icon} and/or {@link OO.ui.IndicatorElement indicator}.
+ * This class is used with OO.ui.SelectWidget to create a selection of mutually exclusive
+ * options. For more information about options and selects, please see the
+ * [OOjs UI documentation on MediaWiki][1].
+ *
+ * @example
+ * // Decorated options in a select widget
+ * var select = new OO.ui.SelectWidget( {
+ * items: [
+ * new OO.ui.DecoratedOptionWidget( {
+ * data: 'a',
+ * label: 'Option with icon',
+ * icon: 'help'
+ * } ),
+ * new OO.ui.DecoratedOptionWidget( {
+ * data: 'b',
+ * label: 'Option with indicator',
+ * indicator: 'next'
+ * } )
+ * ]
+ * } );
+ * $( 'body' ).append( select.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
*
* @class
* @extends OO.ui.OptionWidget
@@ -9543,12 +13799,11 @@ OO.ui.OptionWidget.prototype.getData = function () {
* @mixins OO.ui.IndicatorElement
*
* @constructor
- * @param {Mixed} data Option data
* @param {Object} [config] Configuration options
*/
-OO.ui.DecoratedOptionWidget = function OoUiDecoratedOptionWidget( data, config ) {
+OO.ui.DecoratedOptionWidget = function OoUiDecoratedOptionWidget( config ) {
// Parent constructor
- OO.ui.DecoratedOptionWidget.super.call( this, data, config );
+ OO.ui.DecoratedOptionWidget.super.call( this, config );
// Mixin constructors
OO.ui.IconElement.call( this, config );
@@ -9568,24 +13823,31 @@ OO.mixinClass( OO.ui.OptionWidget, OO.ui.IconElement );
OO.mixinClass( OO.ui.OptionWidget, OO.ui.IndicatorElement );
/**
- * Option widget that looks like a button.
+ * ButtonOptionWidget is a special type of {@link OO.ui.ButtonElement button element} that
+ * can be selected and configured with data. The class is
+ * used with OO.ui.ButtonSelectWidget to create a selection of button options. Please see the
+ * [OOjs UI documentation on MediaWiki] [1] for more information.
*
- * Use together with OO.ui.ButtonSelectWidget.
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Button_selects_and_options
*
* @class
* @extends OO.ui.DecoratedOptionWidget
* @mixins OO.ui.ButtonElement
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
- * @param {Mixed} data Option data
* @param {Object} [config] Configuration options
*/
-OO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( data, config ) {
+OO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( config ) {
+ // Configuration initialization
+ config = $.extend( { tabIndex: -1 }, config );
+
// Parent constructor
- OO.ui.ButtonOptionWidget.super.call( this, data, config );
+ OO.ui.ButtonOptionWidget.super.call( this, config );
// Mixin constructors
OO.ui.ButtonElement.call( this, config );
+ OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$button } ) );
// Initialization
this.$element.addClass( 'oo-ui-buttonOptionWidget' );
@@ -9597,12 +13859,15 @@ OO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( data, config ) {
OO.inheritClass( OO.ui.ButtonOptionWidget, OO.ui.DecoratedOptionWidget );
OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.ButtonElement );
+OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.TabIndexedElement );
/* Static Properties */
// Allow button mouse down events to pass through so they can be handled by the parent select widget
OO.ui.ButtonOptionWidget.static.cancelButtonMouseDownEvents = false;
+OO.ui.ButtonOptionWidget.static.highlightable = false;
+
/* Methods */
/**
@@ -9619,78 +13884,183 @@ OO.ui.ButtonOptionWidget.prototype.setSelected = function ( state ) {
};
/**
- * Item of an OO.ui.MenuWidget.
+ * RadioOptionWidget is an option widget that looks like a radio button.
+ * The class is used with OO.ui.RadioSelectWidget to create a selection of radio options.
+ * Please see the [OOjs UI documentation on MediaWiki] [1] for more information.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Button_selects_and_option
+ *
+ * @class
+ * @extends OO.ui.OptionWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.RadioOptionWidget = function OoUiRadioOptionWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Properties (must be done before parent constructor which calls #setDisabled)
+ this.radio = new OO.ui.RadioInputWidget( { value: config.data, tabIndex: -1 } );
+
+ // Parent constructor
+ OO.ui.RadioOptionWidget.super.call( this, config );
+
+ // Initialization
+ this.$element
+ .addClass( 'oo-ui-radioOptionWidget' )
+ .prepend( this.radio.$element );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.RadioOptionWidget, OO.ui.OptionWidget );
+
+/* Static Properties */
+
+OO.ui.RadioOptionWidget.static.highlightable = false;
+
+OO.ui.RadioOptionWidget.static.scrollIntoViewOnSelect = true;
+
+OO.ui.RadioOptionWidget.static.pressable = false;
+
+OO.ui.RadioOptionWidget.static.tagName = 'label';
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+OO.ui.RadioOptionWidget.prototype.setSelected = function ( state ) {
+ OO.ui.RadioOptionWidget.super.prototype.setSelected.call( this, state );
+
+ this.radio.setSelected( state );
+
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.RadioOptionWidget.prototype.setDisabled = function ( disabled ) {
+ OO.ui.RadioOptionWidget.super.prototype.setDisabled.call( this, disabled );
+
+ this.radio.setDisabled( this.isDisabled() );
+
+ return this;
+};
+
+/**
+ * MenuOptionWidget is an option widget that looks like a menu item. The class is used with
+ * OO.ui.MenuSelectWidget to create a menu of mutually exclusive options. Please see
+ * the [OOjs UI documentation on MediaWiki] [1] for more information.
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
*
* @class
* @extends OO.ui.DecoratedOptionWidget
*
* @constructor
- * @param {Mixed} data Item data
* @param {Object} [config] Configuration options
*/
-OO.ui.MenuItemWidget = function OoUiMenuItemWidget( data, config ) {
+OO.ui.MenuOptionWidget = function OoUiMenuOptionWidget( config ) {
// Configuration initialization
config = $.extend( { icon: 'check' }, config );
// Parent constructor
- OO.ui.MenuItemWidget.super.call( this, data, config );
+ OO.ui.MenuOptionWidget.super.call( this, config );
// Initialization
this.$element
.attr( 'role', 'menuitem' )
- .addClass( 'oo-ui-menuItemWidget' );
+ .addClass( 'oo-ui-menuOptionWidget' );
};
/* Setup */
-OO.inheritClass( OO.ui.MenuItemWidget, OO.ui.DecoratedOptionWidget );
+OO.inheritClass( OO.ui.MenuOptionWidget, OO.ui.DecoratedOptionWidget );
-/**
- * Section to group one or more items in a OO.ui.MenuWidget.
+/* Static Properties */
+
+OO.ui.MenuOptionWidget.static.scrollIntoViewOnSelect = true;
+
+/**
+ * MenuSectionOptionWidgets are used inside {@link OO.ui.MenuSelectWidget menu select widgets} to group one or more related
+ * {@link OO.ui.MenuOptionWidget menu options}. MenuSectionOptionWidgets cannot be highlighted or selected.
+ *
+ * @example
+ * var myDropdown = new OO.ui.DropdownWidget( {
+ * menu: {
+ * items: [
+ * new OO.ui.MenuSectionOptionWidget( {
+ * label: 'Dogs'
+ * } ),
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'corgi',
+ * label: 'Welsh Corgi'
+ * } ),
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'poodle',
+ * label: 'Standard Poodle'
+ * } ),
+ * new OO.ui.MenuSectionOptionWidget( {
+ * label: 'Cats'
+ * } ),
+ * new OO.ui.MenuOptionWidget( {
+ * data: 'lion',
+ * label: 'Lion'
+ * } )
+ * ]
+ * }
+ * } );
+ * $( 'body' ).append( myDropdown.$element );
+ *
*
* @class
* @extends OO.ui.DecoratedOptionWidget
*
* @constructor
- * @param {Mixed} data Item data
* @param {Object} [config] Configuration options
*/
-OO.ui.MenuSectionItemWidget = function OoUiMenuSectionItemWidget( data, config ) {
+OO.ui.MenuSectionOptionWidget = function OoUiMenuSectionOptionWidget( config ) {
// Parent constructor
- OO.ui.MenuSectionItemWidget.super.call( this, data, config );
+ OO.ui.MenuSectionOptionWidget.super.call( this, config );
// Initialization
- this.$element.addClass( 'oo-ui-menuSectionItemWidget' );
+ this.$element.addClass( 'oo-ui-menuSectionOptionWidget' );
};
/* Setup */
-OO.inheritClass( OO.ui.MenuSectionItemWidget, OO.ui.DecoratedOptionWidget );
+OO.inheritClass( OO.ui.MenuSectionOptionWidget, OO.ui.DecoratedOptionWidget );
/* Static Properties */
-OO.ui.MenuSectionItemWidget.static.selectable = false;
+OO.ui.MenuSectionOptionWidget.static.selectable = false;
-OO.ui.MenuSectionItemWidget.static.highlightable = false;
+OO.ui.MenuSectionOptionWidget.static.highlightable = false;
/**
- * Items for an OO.ui.OutlineWidget.
+ * OutlineOptionWidget is an item in an {@link OO.ui.OutlineSelectWidget OutlineSelectWidget}.
+ *
+ * Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}, which contain
+ * {@link OO.ui.PageLayout page layouts}. See {@link OO.ui.BookletLayout BookletLayout}
+ * for an example.
*
* @class
* @extends OO.ui.DecoratedOptionWidget
*
* @constructor
- * @param {Mixed} data Item data
* @param {Object} [config] Configuration options
* @cfg {number} [level] Indentation level
- * @cfg {boolean} [movable] Allow modification from outline controls
+ * @cfg {boolean} [movable] Allow modification from {@link OO.ui.OutlineControlsWidget outline controls}.
*/
-OO.ui.OutlineItemWidget = function OoUiOutlineItemWidget( data, config ) {
- // Config intialization
+OO.ui.OutlineOptionWidget = function OoUiOutlineOptionWidget( config ) {
+ // Configuration initialization
config = config || {};
// Parent constructor
- OO.ui.OutlineItemWidget.super.call( this, data, config );
+ OO.ui.OutlineOptionWidget.super.call( this, config );
// Properties
this.level = 0;
@@ -9698,45 +14068,45 @@ OO.ui.OutlineItemWidget = function OoUiOutlineItemWidget( data, config ) {
this.removable = !!config.removable;
// Initialization
- this.$element.addClass( 'oo-ui-outlineItemWidget' );
+ this.$element.addClass( 'oo-ui-outlineOptionWidget' );
this.setLevel( config.level );
};
/* Setup */
-OO.inheritClass( OO.ui.OutlineItemWidget, OO.ui.DecoratedOptionWidget );
+OO.inheritClass( OO.ui.OutlineOptionWidget, OO.ui.DecoratedOptionWidget );
/* Static Properties */
-OO.ui.OutlineItemWidget.static.highlightable = false;
+OO.ui.OutlineOptionWidget.static.highlightable = false;
-OO.ui.OutlineItemWidget.static.scrollIntoViewOnSelect = true;
+OO.ui.OutlineOptionWidget.static.scrollIntoViewOnSelect = true;
-OO.ui.OutlineItemWidget.static.levelClass = 'oo-ui-outlineItemWidget-level-';
+OO.ui.OutlineOptionWidget.static.levelClass = 'oo-ui-outlineOptionWidget-level-';
-OO.ui.OutlineItemWidget.static.levels = 3;
+OO.ui.OutlineOptionWidget.static.levels = 3;
/* Methods */
/**
* Check if item is movable.
*
- * Movablilty is used by outline controls.
+ * Movability is used by {@link OO.ui.OutlineControlsWidget outline controls}.
*
* @return {boolean} Item is movable
*/
-OO.ui.OutlineItemWidget.prototype.isMovable = function () {
+OO.ui.OutlineOptionWidget.prototype.isMovable = function () {
return this.movable;
};
/**
* Check if item is removable.
*
- * Removablilty is used by outline controls.
+ * Removability is used by {@link OO.ui.OutlineControlsWidget outline controls}.
*
* @return {boolean} Item is removable
*/
-OO.ui.OutlineItemWidget.prototype.isRemovable = function () {
+OO.ui.OutlineOptionWidget.prototype.isRemovable = function () {
return this.removable;
};
@@ -9745,33 +14115,35 @@ OO.ui.OutlineItemWidget.prototype.isRemovable = function () {
*
* @return {number} Indentation level
*/
-OO.ui.OutlineItemWidget.prototype.getLevel = function () {
+OO.ui.OutlineOptionWidget.prototype.getLevel = function () {
return this.level;
};
/**
* Set movability.
*
- * Movablilty is used by outline controls.
+ * Movability is used by {@link OO.ui.OutlineControlsWidget outline controls}.
*
* @param {boolean} movable Item is movable
* @chainable
*/
-OO.ui.OutlineItemWidget.prototype.setMovable = function ( movable ) {
+OO.ui.OutlineOptionWidget.prototype.setMovable = function ( movable ) {
this.movable = !!movable;
+ this.updateThemeClasses();
return this;
};
/**
* Set removability.
*
- * Removablilty is used by outline controls.
+ * Removability is used by {@link OO.ui.OutlineControlsWidget outline controls}.
*
* @param {boolean} movable Item is removable
* @chainable
*/
-OO.ui.OutlineItemWidget.prototype.setRemovable = function ( removable ) {
+OO.ui.OutlineOptionWidget.prototype.setRemovable = function ( removable ) {
this.removable = !!removable;
+ this.updateThemeClasses();
return this;
};
@@ -9781,7 +14153,7 @@ OO.ui.OutlineItemWidget.prototype.setRemovable = function ( removable ) {
* @param {number} [level=0] Indentation level, in the range of [0,#maxLevel]
* @chainable
*/
-OO.ui.OutlineItemWidget.prototype.setLevel = function ( level ) {
+OO.ui.OutlineOptionWidget.prototype.setLevel = function ( level ) {
var levels = this.constructor.static.levels,
levelClass = this.constructor.static.levelClass,
i = levels;
@@ -9794,12 +14166,61 @@ OO.ui.OutlineItemWidget.prototype.setLevel = function ( level ) {
this.$element.removeClass( levelClass + i );
}
}
+ this.updateThemeClasses();
return this;
};
/**
- * Container for content that is overlaid and positioned absolutely.
+ * TabOptionWidget is an item in a {@link OO.ui.TabSelectWidget TabSelectWidget}.
+ *
+ * Currently, this class is only used by {@link OO.ui.IndexLayout index layouts}, which contain
+ * {@link OO.ui.CardLayout card layouts}. See {@link OO.ui.IndexLayout IndexLayout}
+ * for an example.
+ *
+ * @class
+ * @extends OO.ui.OptionWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.TabOptionWidget = function OoUiTabOptionWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.TabOptionWidget.super.call( this, config );
+
+ // Initialization
+ this.$element.addClass( 'oo-ui-tabOptionWidget' );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.TabOptionWidget, OO.ui.OptionWidget );
+
+/* Static Properties */
+
+OO.ui.TabOptionWidget.static.highlightable = false;
+
+/**
+ * PopupWidget is a container for content. The popup is overlaid and positioned absolutely.
+ * By default, each popup has an anchor that points toward its origin.
+ * Please see the [OOjs UI documentation on Mediawiki] [1] for more information and examples.
+ *
+ * @example
+ * // A popup widget.
+ * var popup = new OO.ui.PopupWidget( {
+ * $content: $( '<p>Hi there!</p>' ),
+ * padded: true,
+ * width: 300
+ * } );
+ *
+ * $( 'body' ).append( popup.$element );
+ * // To display the popup, toggle the visibility to 'true'.
+ * popup.toggle( true );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Popups
*
* @class
* @extends OO.ui.Widget
@@ -9808,43 +14229,60 @@ OO.ui.OutlineItemWidget.prototype.setLevel = function ( level ) {
* @constructor
* @param {Object} [config] Configuration options
* @cfg {number} [width=320] Width of popup in pixels
- * @cfg {number} [height] Height of popup, omit to use automatic height
+ * @cfg {number} [height] Height of popup in pixels. Omit to use the automatic height.
* @cfg {boolean} [anchor=true] Show anchor 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 {string} [align='center'] Alignment of the popup: `center`, `force-left`, `force-right`, `backwards` or `forwards`.
+ * If the popup is forced-left the popup body is leaning towards the left. For force-right alignment, the body of the
+ * popup is leaning towards the right of the screen.
+ * Using 'backwards' is a logical direction which will result in the popup leaning towards the beginning of the sentence
+ * in the given language, which means it will flip to the correct positioning in right-to-left languages.
+ * Using 'forward' will also result in a logical alignment where the body of the popup leans towards the end of the
+ * sentence in the given language.
+ * @cfg {jQuery} [$container] Constrain the popup to the boundaries of the specified container.
+ * See the [OOjs UI docs on MediaWiki][3] for an example.
+ * [3]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Popups#containerExample
+ * @cfg {number} [containerPadding=10] Padding between the popup and its container, specified as a number of pixels.
* @cfg {jQuery} [$content] Content to append to the popup's body
- * @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
- * @cfg {boolean} [padded] Add padding to the body
+ * @cfg {boolean} [autoClose=false] Automatically close the popup when it loses focus.
+ * @cfg {jQuery} [$autoCloseIgnore] Elements that will not close the popup when clicked.
+ * This config option is only relevant if #autoClose is set to `true`. See the [OOjs UI docs on MediaWiki][2]
+ * for an example.
+ * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Popups#autocloseExample
+ * @cfg {boolean} [head] Show a popup header that contains a #label (if specified) and close
+ * button.
+ * @cfg {boolean} [padded] Add padding to the popup's body
*/
OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
- // Config intialization
+ // Configuration initialization
config = config || {};
// Parent constructor
OO.ui.PopupWidget.super.call( this, config );
+ // Properties (must be set before ClippableElement constructor call)
+ this.$body = $( '<div>' );
+
// Mixin constructors
OO.ui.LabelElement.call( this, config );
- OO.ui.ClippableElement.call( this, config );
+ OO.ui.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$body } ) );
// Properties
- this.visible = false;
- this.$popup = this.$( '<div>' );
- this.$head = this.$( '<div>' );
- this.$body = this.$( '<div>' );
- this.$anchor = this.$( '<div>' );
- this.$container = config.$container; // If undefined, will be computed lazily in updateDimensions()
+ this.$popup = $( '<div>' );
+ this.$head = $( '<div>' );
+ this.$anchor = $( '<div>' );
+ // If undefined, will be computed lazily in updateDimensions()
+ this.$container = config.$container;
+ this.containerPadding = config.containerPadding !== undefined ? config.containerPadding : 10;
this.autoClose = !!config.autoClose;
this.$autoCloseIgnore = config.$autoCloseIgnore;
this.transitionTimeout = null;
this.anchor = null;
this.width = config.width !== undefined ? config.width : 320;
this.height = config.height !== undefined ? config.height : null;
- this.align = config.align || 'center';
- this.closeButton = new OO.ui.ButtonWidget( { $: this.$, framed: false, icon: 'close' } );
- this.onMouseDownHandler = OO.ui.bind( this.onMouseDown, this );
+ this.setAlignment( config.align );
+ this.closeButton = new OO.ui.ButtonWidget( { framed: false, icon: 'close' } );
+ this.onMouseDownHandler = this.onMouseDown.bind( this );
+ this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );
// Events
this.closeButton.connect( this, { click: 'onCloseButtonClick' } );
@@ -9857,13 +14295,12 @@ OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
.addClass( 'oo-ui-popupWidget-head' )
.append( this.$label, this.closeButton.$element );
if ( !config.head ) {
- this.$head.hide();
+ this.$head.addClass( 'oo-ui-element-hidden' );
}
this.$popup
.addClass( 'oo-ui-popupWidget-popup' )
.append( this.$head, this.$body );
this.$element
- .hide()
.addClass( 'oo-ui-popupWidget' )
.append( this.$popup, this.$anchor );
// Move content, which was added to #$element by OO.ui.Widget, to the body
@@ -9873,7 +14310,12 @@ OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
if ( config.padded ) {
this.$body.addClass( 'oo-ui-popupWidget-body-padded' );
}
- this.setClippableElement( this.$body );
+
+ // Initially hidden - using #toggle may cause errors if subclasses override toggle with methods
+ // that reference properties not initialized at that time of parent class construction
+ // TODO: Find a better way to handle post-constructor setup
+ this.visible = false;
+ this.$element.addClass( 'oo-ui-element-hidden' );
};
/* Setup */
@@ -9882,27 +14324,18 @@ OO.inheritClass( OO.ui.PopupWidget, OO.ui.Widget );
OO.mixinClass( OO.ui.PopupWidget, OO.ui.LabelElement );
OO.mixinClass( OO.ui.PopupWidget, OO.ui.ClippableElement );
-/* Events */
-
-/**
- * @event hide
- */
-
-/**
- * @event show
- */
-
/* Methods */
/**
* Handles mouse down events.
*
- * @param {jQuery.Event} e Mouse down event
+ * @private
+ * @param {MouseEvent} e Mouse down event
*/
OO.ui.PopupWidget.prototype.onMouseDown = function ( e ) {
if (
this.isVisible() &&
- !$.contains( this.$element[0], e.target ) &&
+ !$.contains( this.$element[ 0 ], e.target ) &&
( !this.$autoCloseIgnore || !this.$autoCloseIgnore.has( e.target ).length )
) {
this.toggle( false );
@@ -9911,6 +14344,8 @@ OO.ui.PopupWidget.prototype.onMouseDown = function ( e ) {
/**
* Bind mouse down listener.
+ *
+ * @private
*/
OO.ui.PopupWidget.prototype.bindMouseDownListener = function () {
// Capture clicks outside popup
@@ -9919,6 +14354,8 @@ OO.ui.PopupWidget.prototype.bindMouseDownListener = function () {
/**
* Handles close button click events.
+ *
+ * @private
*/
OO.ui.PopupWidget.prototype.onCloseButtonClick = function () {
if ( this.isVisible() ) {
@@ -9928,13 +14365,50 @@ OO.ui.PopupWidget.prototype.onCloseButtonClick = function () {
/**
* Unbind mouse down listener.
+ *
+ * @private
*/
OO.ui.PopupWidget.prototype.unbindMouseDownListener = function () {
this.getElementWindow().removeEventListener( 'mousedown', this.onMouseDownHandler, true );
};
/**
- * Set whether to show a anchor.
+ * Handles key down events.
+ *
+ * @private
+ * @param {KeyboardEvent} e Key down event
+ */
+OO.ui.PopupWidget.prototype.onDocumentKeyDown = function ( e ) {
+ if (
+ e.which === OO.ui.Keys.ESCAPE &&
+ this.isVisible()
+ ) {
+ this.toggle( false );
+ e.preventDefault();
+ e.stopPropagation();
+ }
+};
+
+/**
+ * Bind key down listener.
+ *
+ * @private
+ */
+OO.ui.PopupWidget.prototype.bindKeyDownListener = function () {
+ this.getElementWindow().addEventListener( 'keydown', this.onDocumentKeyDownHandler, true );
+};
+
+/**
+ * Unbind key down listener.
+ *
+ * @private
+ */
+OO.ui.PopupWidget.prototype.unbindKeyDownListener = function () {
+ this.getElementWindow().removeEventListener( 'keydown', this.onDocumentKeyDownHandler, true );
+};
+
+/**
+ * Show, hide, or toggle the visibility of the anchor.
*
* @param {boolean} [show] Show anchor, omit to toggle
*/
@@ -9952,9 +14426,9 @@ OO.ui.PopupWidget.prototype.toggleAnchor = function ( show ) {
};
/**
- * Check if showing a anchor.
+ * Check if the anchor is visible.
*
- * @return {boolean} anchor is visible
+ * @return {boolean} Anchor is visible
*/
OO.ui.PopupWidget.prototype.hasAnchor = function () {
return this.anchor;
@@ -9975,6 +14449,7 @@ OO.ui.PopupWidget.prototype.toggle = function ( show ) {
if ( show ) {
if ( this.autoClose ) {
this.bindMouseDownListener();
+ this.bindKeyDownListener();
}
this.updateDimensions();
this.toggleClipping( true );
@@ -9982,6 +14457,7 @@ OO.ui.PopupWidget.prototype.toggle = function ( show ) {
this.toggleClipping( false );
if ( this.autoClose ) {
this.unbindMouseDownListener();
+ this.unbindKeyDownListener();
}
}
}
@@ -9994,8 +14470,8 @@ OO.ui.PopupWidget.prototype.toggle = function ( show ) {
*
* Changing the size may also change the popup's position depending on the alignment.
*
- * @param {number} width Width
- * @param {number} height Height
+ * @param {number} width Width in pixels
+ * @param {number} height Height in pixels
* @param {boolean} [transition=false] Use a smooth transition
* @chainable
*/
@@ -10019,12 +14495,12 @@ OO.ui.PopupWidget.prototype.setSize = function ( width, height, transition ) {
OO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) {
var popupOffset, originOffset, containerLeft, containerWidth, containerRight,
popupLeft, popupRight, overlapLeft, overlapRight, anchorWidth,
- widget = this,
- padding = 10;
+ align = this.align,
+ widget = this;
if ( !this.$container ) {
// Lazy-initialize $container if not specified in constructor
- this.$container = this.$( this.getClosestScrollableElementContainer() );
+ this.$container = $( this.getClosestScrollableElementContainer() );
}
// Set height and width before measuring things, since it might cause our measurements
@@ -10034,16 +14510,26 @@ OO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) {
height: this.height !== null ? this.height : 'auto'
} );
+ // If we are in RTL, we need to flip the alignment, unless it is center
+ if ( align === 'forwards' || align === 'backwards' ) {
+ if ( this.$container.css( 'direction' ) === 'rtl' ) {
+ align = ( { forwards: 'force-left', backwards: 'force-right' } )[ this.align ];
+ } else {
+ align = ( { forwards: 'force-right', backwards: 'force-left' } )[ this.align ];
+ }
+
+ }
+
// Compute initial popupOffset based on alignment
- popupOffset = this.width * ( { left: 0, center: -0.5, right: -1 } )[this.align];
+ popupOffset = this.width * ( { 'force-left': -1, center: -0.5, 'force-right': 0 } )[ align ];
// Figure out if this will cause the popup to go beyond the edge of the container
- originOffset = Math.round( this.$element.offset().left );
- containerLeft = Math.round( this.$container.offset().left );
+ originOffset = this.$element.offset().left;
+ containerLeft = this.$container.offset().left;
containerWidth = this.$container.innerWidth();
containerRight = containerLeft + containerWidth;
- popupLeft = popupOffset - padding;
- popupRight = popupOffset + padding + this.width + padding;
+ popupLeft = popupOffset - this.containerPadding;
+ popupRight = popupOffset + this.containerPadding + this.width + this.containerPadding;
overlapLeft = ( originOffset + popupLeft ) - containerLeft;
overlapRight = containerRight - ( originOffset + popupRight );
@@ -10055,11 +14541,13 @@ OO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) {
}
// Adjust offset to avoid anchor being rendered too close to the edge
- anchorWidth = this.$anchor.width();
- if ( this.align === 'right' ) {
- popupOffset += anchorWidth;
- } else if ( this.align === 'left' ) {
- popupOffset -= anchorWidth;
+ // $anchor.width() doesn't work with the pure CSS anchor (returns 0)
+ // TODO: Find a measurement that works for CSS anchors and image anchors
+ anchorWidth = this.$anchor[ 0 ].scrollWidth * 2;
+ if ( popupOffset + this.width < anchorWidth ) {
+ popupOffset = anchorWidth - this.width;
+ } else if ( -popupOffset < anchorWidth ) {
+ popupOffset = -anchorWidth;
}
// Prevent transition from being interrupted
@@ -10070,7 +14558,7 @@ OO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) {
}
// Position body relative to anchor
- this.$popup.css( 'left', popupOffset );
+ this.$popup.css( 'margin-left', popupOffset );
if ( transition ) {
// Prevent transitioning after transition is complete
@@ -10082,14 +14570,143 @@ OO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) {
this.$element.removeClass( 'oo-ui-popupWidget-transitioning' );
}
+ // Reevaluate clipping state since we've relocated and resized the popup
+ this.clip();
+
return this;
};
/**
- * Search widget.
+ * Set popup alignment
+ * @param {string} align Alignment of the popup, `center`, `force-left`, `force-right`,
+ * `backwards` or `forwards`.
+ */
+OO.ui.PopupWidget.prototype.setAlignment = function ( align ) {
+ // Validate alignment and transform deprecated values
+ if ( [ 'left', 'right', 'force-left', 'force-right', 'backwards', 'forwards', 'center' ].indexOf( align ) > -1 ) {
+ this.align = { left: 'force-right', right: 'force-left' }[ align ] || align;
+ } else {
+ this.align = 'center';
+ }
+};
+
+/**
+ * Get popup alignment
+ * @return {string} align Alignment of the popup, `center`, `force-left`, `force-right`,
+ * `backwards` or `forwards`.
+ */
+OO.ui.PopupWidget.prototype.getAlignment = function () {
+ return this.align;
+};
+
+/**
+ * Progress bars visually display the status of an operation, such as a download,
+ * and can be either determinate or indeterminate:
+ *
+ * - **determinate** process bars show the percent of an operation that is complete.
*
- * Search widgets combine a query input, placed above, and a results selection widget, placed below.
- * Results are cleared and populated each time the query is changed.
+ * - **indeterminate** process bars use a visual display of motion to indicate that an operation
+ * is taking place. Because the extent of an indeterminate operation is unknown, the bar does
+ * not use percentages.
+ *
+ * The value of the `progress` configuration determines whether the bar is determinate or indeterminate.
+ *
+ * @example
+ * // Examples of determinate and indeterminate progress bars.
+ * var progressBar1 = new OO.ui.ProgressBarWidget( {
+ * progress: 33
+ * } );
+ * var progressBar2 = new OO.ui.ProgressBarWidget();
+ *
+ * // Create a FieldsetLayout to layout progress bars
+ * var fieldset = new OO.ui.FieldsetLayout;
+ * fieldset.addItems( [
+ * new OO.ui.FieldLayout( progressBar1, {label: 'Determinate', align: 'top'}),
+ * new OO.ui.FieldLayout( progressBar2, {label: 'Indeterminate', align: 'top'})
+ * ] );
+ * $( 'body' ).append( fieldset.$element );
+ *
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {number|boolean} [progress=false] The type of progress bar (determinate or indeterminate).
+ * To create a determinate progress bar, specify a number that reflects the initial percent complete.
+ * By default, the progress bar is indeterminate.
+ */
+OO.ui.ProgressBarWidget = function OoUiProgressBarWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.ProgressBarWidget.super.call( this, config );
+
+ // Properties
+ this.$bar = $( '<div>' );
+ this.progress = null;
+
+ // Initialization
+ this.setProgress( config.progress !== undefined ? config.progress : false );
+ this.$bar.addClass( 'oo-ui-progressBarWidget-bar' );
+ this.$element
+ .attr( {
+ role: 'progressbar',
+ 'aria-valuemin': 0,
+ 'aria-valuemax': 100
+ } )
+ .addClass( 'oo-ui-progressBarWidget' )
+ .append( this.$bar );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.ProgressBarWidget, OO.ui.Widget );
+
+/* Static Properties */
+
+OO.ui.ProgressBarWidget.static.tagName = 'div';
+
+/* Methods */
+
+/**
+ * Get the percent of the progress that has been completed. Indeterminate progresses will return `false`.
+ *
+ * @return {number|boolean} Progress percent
+ */
+OO.ui.ProgressBarWidget.prototype.getProgress = function () {
+ return this.progress;
+};
+
+/**
+ * Set the percent of the process completed or `false` for an indeterminate process.
+ *
+ * @param {number|boolean} progress Progress percent or `false` for indeterminate
+ */
+OO.ui.ProgressBarWidget.prototype.setProgress = function ( progress ) {
+ this.progress = progress;
+
+ if ( progress !== false ) {
+ this.$bar.css( 'width', this.progress + '%' );
+ this.$element.attr( 'aria-valuenow', this.progress );
+ } else {
+ this.$bar.css( 'width', '' );
+ this.$element.removeAttr( 'aria-valuenow' );
+ }
+ this.$element.toggleClass( 'oo-ui-progressBarWidget-indeterminate', !progress );
+};
+
+/**
+ * SearchWidgets combine a {@link OO.ui.TextInputWidget text input field}, where users can type a search query,
+ * and a {@link OO.ui.TextInputMenuSelectWidget menu} of search results, which is displayed beneath the query
+ * field. Unlike {@link OO.ui.LookupElement lookup menus}, search result menus are always visible to the user.
+ * Users can choose an item from the menu or type a query into the text field to search for a matching result item.
+ * In general, search widgets are used inside a separate {@link OO.ui.Dialog dialog} window.
+ *
+ * Each time the query is changed, the search result menu is cleared and repopulated. Please see
+ * the [OOjs UI demos][1] for an example.
+ *
+ * [1]: https://tools.wmflabs.org/oojs-ui/oojs-ui/demos/#dialogs-mediawiki-vector-ltr
*
* @class
* @extends OO.ui.Widget
@@ -10100,7 +14717,7 @@ OO.ui.PopupWidget.prototype.updateDimensions = function ( transition ) {
* @cfg {string} [value] Initial query value
*/
OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
- // Configuration intialization
+ // Configuration initialization
config = config || {};
// Parent constructor
@@ -10108,14 +14725,13 @@ OO.ui.SearchWidget = function OoUiSearchWidget( 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>' );
+ this.results = new OO.ui.SelectWidget();
+ this.$query = $( '<div>' );
+ this.$results = $( '<div>' );
// Events
this.query.connect( this, {
@@ -10126,7 +14742,7 @@ OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
highlight: 'onResultsHighlight',
select: 'onResultsSelect'
} );
- this.query.$input.on( 'keydown', OO.ui.bind( this.onQueryKeydown, this ) );
+ this.query.$input.on( 'keydown', this.onQueryKeydown.bind( this ) );
// Initialization
this.$query
@@ -10147,12 +14763,22 @@ OO.inheritClass( OO.ui.SearchWidget, OO.ui.Widget );
/* Events */
/**
+ * A 'highlight' event is emitted when an item is highlighted. The highlight indicates which
+ * item will be selected. When a user mouses over a menu item, it is highlighted. If a search
+ * string is typed into the query field instead, the first menu item that matches the query
+ * will be highlighted.
+
* @event highlight
+ * @deprecated Connect straight to getResults() events instead
* @param {Object|null} item Item data or null if no item is highlighted
*/
/**
+ * A 'select' event is emitted when an item is selected. A menu item is selected when it is clicked,
+ * or when a user types a search query, a menu result is highlighted, and the user presses enter.
+ *
* @event select
+ * @deprecated Connect straight to getResults() events instead
* @param {Object|null} item Item data or null if no item is selected
*/
@@ -10161,6 +14787,7 @@ OO.inheritClass( OO.ui.SearchWidget, OO.ui.Widget );
/**
* Handle query key down events.
*
+ * @private
* @param {jQuery.Event} e Key down event
*/
OO.ui.SearchWidget.prototype.onQueryKeydown = function ( e ) {
@@ -10183,6 +14810,7 @@ OO.ui.SearchWidget.prototype.onQueryKeydown = function ( e ) {
*
* Clears existing results. Subclasses should repopulate items according to new query.
*
+ * @private
* @param {string} value New value
*/
OO.ui.SearchWidget.prototype.onQueryChange = function () {
@@ -10195,6 +14823,7 @@ OO.ui.SearchWidget.prototype.onQueryChange = function () {
*
* Selects highlighted item.
*
+ * @private
* @param {string} value New value
*/
OO.ui.SearchWidget.prototype.onQueryEnter = function () {
@@ -10205,6 +14834,8 @@ OO.ui.SearchWidget.prototype.onQueryEnter = function () {
/**
* Handle select widget highlight events.
*
+ * @private
+ * @deprecated Connect straight to getResults() events instead
* @param {OO.ui.OptionWidget} item Highlighted item
* @fires highlight
*/
@@ -10215,6 +14846,8 @@ OO.ui.SearchWidget.prototype.onResultsHighlight = function ( item ) {
/**
* Handle select widget select events.
*
+ * @private
+ * @deprecated Connect straight to getResults() events instead
* @param {OO.ui.OptionWidget} item Selected item
* @fires select
*/
@@ -10232,32 +14865,59 @@ OO.ui.SearchWidget.prototype.getQuery = function () {
};
/**
- * Get the results list.
+ * Get the search results menu.
*
- * @return {OO.ui.SelectWidget} Select list
+ * @return {OO.ui.SelectWidget} Menu of search results
*/
OO.ui.SearchWidget.prototype.getResults = function () {
return this.results;
};
/**
- * Generic selection of options.
- *
- * Items can contain any rendering, and are uniquely identified by a has of thier data. Any widget
- * that provides options, from which the user must choose one, should be built on this class.
- *
- * Use together with OO.ui.OptionWidget.
+ * A SelectWidget is of a generic selection of options. The OOjs UI library contains several types of
+ * select widgets, including {@link OO.ui.ButtonSelectWidget button selects},
+ * {@link OO.ui.RadioSelectWidget radio selects}, and {@link OO.ui.MenuSelectWidget
+ * menu selects}.
+ *
+ * This class should be used together with OO.ui.OptionWidget or OO.ui.DecoratedOptionWidget. For more
+ * information, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * @example
+ * // Example of a select widget with three options
+ * var select = new OO.ui.SelectWidget( {
+ * items: [
+ * new OO.ui.OptionWidget( {
+ * data: 'a',
+ * label: 'Option One',
+ * } ),
+ * new OO.ui.OptionWidget( {
+ * data: 'b',
+ * label: 'Option Two',
+ * } ),
+ * new OO.ui.OptionWidget( {
+ * data: 'c',
+ * label: 'Option Three',
+ * } )
+ * ]
+ * } );
+ * $( 'body' ).append( select.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
*
+ * @abstract
* @class
* @extends OO.ui.Widget
* @mixins OO.ui.GroupElement
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {OO.ui.OptionWidget[]} [items] Options to add
+ * @cfg {OO.ui.OptionWidget[]} [items] An array of options to add to the select.
+ * Options are created with {@link OO.ui.OptionWidget OptionWidget} classes. See
+ * the [OOjs UI documentation on MediaWiki] [2] for examples.
+ * [2]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
*/
OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
- // Config intialization
+ // Configuration initialization
config = config || {};
// Parent constructor
@@ -10269,20 +14929,22 @@ OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
// Properties
this.pressed = false;
this.selecting = null;
- this.hashes = {};
- this.onMouseUpHandler = OO.ui.bind( this.onMouseUp, this );
- this.onMouseMoveHandler = OO.ui.bind( this.onMouseMove, this );
+ this.onMouseUpHandler = this.onMouseUp.bind( this );
+ this.onMouseMoveHandler = this.onMouseMove.bind( this );
+ this.onKeyDownHandler = this.onKeyDown.bind( this );
// Events
this.$element.on( {
- mousedown: OO.ui.bind( this.onMouseDown, this ),
- mouseover: OO.ui.bind( this.onMouseOver, this ),
- mouseleave: OO.ui.bind( this.onMouseLeave, this )
+ mousedown: this.onMouseDown.bind( this ),
+ mouseover: this.onMouseOver.bind( this ),
+ mouseleave: this.onMouseLeave.bind( this )
} );
// Initialization
- this.$element.addClass( 'oo-ui-selectWidget oo-ui-selectWidget-depressed' );
- if ( $.isArray( config.items ) ) {
+ this.$element
+ .addClass( 'oo-ui-selectWidget oo-ui-selectWidget-depressed' )
+ .attr( 'role', 'listbox' );
+ if ( Array.isArray( config.items ) ) {
this.addItems( config.items );
}
};
@@ -10299,32 +14961,50 @@ OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupWidget );
/**
* @event highlight
+ *
+ * A `highlight` event is emitted when the highlight is changed with the #highlightItem method.
+ *
* @param {OO.ui.OptionWidget|null} item Highlighted item
*/
/**
* @event press
+ *
+ * A `press` event is emitted when the #pressItem method is used to programmatically modify the
+ * pressed state of an option.
+ *
* @param {OO.ui.OptionWidget|null} item Pressed item
*/
/**
* @event select
+ *
+ * A `select` event is emitted when the selection is modified programmatically with the #selectItem method.
+ *
* @param {OO.ui.OptionWidget|null} item Selected item
*/
/**
* @event choose
- * @param {OO.ui.OptionWidget|null} item Chosen item
+ * A `choose` event is emitted when an item is chosen with the #chooseItem method.
+ * @param {OO.ui.OptionWidget} item Chosen item
*/
/**
* @event add
+ *
+ * An `add` event is emitted when options are added to the select with the #addItems method.
+ *
* @param {OO.ui.OptionWidget[]} items Added items
- * @param {number} index Index items were added at
+ * @param {number} index Index of insertion point
*/
/**
* @event remove
+ *
+ * A `remove` event is emitted when options are removed from the select with the #clearItems
+ * or #removeItems methods.
+ *
* @param {OO.ui.OptionWidget[]} items Removed items
*/
@@ -10445,6 +15125,82 @@ OO.ui.SelectWidget.prototype.onMouseLeave = function () {
};
/**
+ * Handle key down events.
+ *
+ * @protected
+ * @param {jQuery.Event} e Key down event
+ */
+OO.ui.SelectWidget.prototype.onKeyDown = function ( e ) {
+ var nextItem,
+ handled = false,
+ currentItem = this.getHighlightedItem() || this.getSelectedItem();
+
+ if ( !this.isDisabled() && this.isVisible() ) {
+ switch ( e.keyCode ) {
+ case OO.ui.Keys.ENTER:
+ if ( currentItem && currentItem.constructor.static.highlightable ) {
+ // Was only highlighted, now let's select it. No-op if already selected.
+ this.chooseItem( currentItem );
+ handled = true;
+ }
+ break;
+ case OO.ui.Keys.UP:
+ case OO.ui.Keys.LEFT:
+ nextItem = this.getRelativeSelectableItem( currentItem, -1 );
+ handled = true;
+ break;
+ case OO.ui.Keys.DOWN:
+ case OO.ui.Keys.RIGHT:
+ nextItem = this.getRelativeSelectableItem( currentItem, 1 );
+ handled = true;
+ break;
+ case OO.ui.Keys.ESCAPE:
+ case OO.ui.Keys.TAB:
+ if ( currentItem && currentItem.constructor.static.highlightable ) {
+ currentItem.setHighlighted( false );
+ }
+ this.unbindKeyDownListener();
+ // Don't prevent tabbing away / defocusing
+ handled = false;
+ break;
+ }
+
+ if ( nextItem ) {
+ if ( nextItem.constructor.static.highlightable ) {
+ this.highlightItem( nextItem );
+ } else {
+ this.chooseItem( nextItem );
+ }
+ nextItem.scrollElementIntoView();
+ }
+
+ if ( handled ) {
+ // Can't just return false, because e is not always a jQuery event
+ e.preventDefault();
+ e.stopPropagation();
+ }
+ }
+};
+
+/**
+ * Bind key down listener.
+ *
+ * @protected
+ */
+OO.ui.SelectWidget.prototype.bindKeyDownListener = function () {
+ this.getElementWindow().addEventListener( 'keydown', this.onKeyDownHandler, true );
+};
+
+/**
+ * Unbind key down listener.
+ *
+ * @protected
+ */
+OO.ui.SelectWidget.prototype.unbindKeyDownListener = function () {
+ this.getElementWindow().removeEventListener( 'keydown', this.onKeyDownHandler, true );
+};
+
+/**
* Get the closest item to a jQuery.Event.
*
* @private
@@ -10452,11 +15208,7 @@ OO.ui.SelectWidget.prototype.onMouseLeave = function () {
* @return {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;
+ return $( e.target ).closest( '.oo-ui-optionWidget' ).data( 'oo-ui-optionWidget' ) || null;
};
/**
@@ -10468,8 +15220,8 @@ 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];
+ if ( this.items[ i ].isSelected() ) {
+ return this.items[ i ];
}
}
return null;
@@ -10484,32 +15236,20 @@ 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];
+ if ( this.items[ i ].isHighlighted() ) {
+ return this.items[ i ];
}
}
return null;
};
/**
- * Get an existing item with equivilant data.
- *
- * @param {Object} data Item data to search for
- * @return {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;
-};
-
-/**
* Toggle pressed state.
*
+ * Press is a state that occurs when a user mouses down on an item, but
+ * has not yet let go of the mouse. The item may appear selected, but it will not be selected
+ * until the user releases the mouse.
+ *
* @param {boolean} pressed An option is being pressed
*/
OO.ui.SelectWidget.prototype.togglePressed = function ( pressed ) {
@@ -10525,11 +15265,10 @@ OO.ui.SelectWidget.prototype.togglePressed = function ( pressed ) {
};
/**
- * Highlight an item.
+ * Highlight an option. If the `item` param is omitted, no options will be highlighted
+ * and any existing highlight will be removed. The highlight is mutually exclusive.
*
- * Highlighting is mutually exclusive.
- *
- * @param {OO.ui.OptionWidget} [item] Item to highlight, omit to deselect all
+ * @param {OO.ui.OptionWidget} [item] Item to highlight, omit for no highlight
* @fires highlight
* @chainable
*/
@@ -10538,9 +15277,9 @@ OO.ui.SelectWidget.prototype.highlightItem = function ( item ) {
changed = false;
for ( i = 0, len = this.items.length; i < len; i++ ) {
- highlighted = this.items[i] === item;
- if ( this.items[i].isHighlighted() !== highlighted ) {
- this.items[i].setHighlighted( highlighted );
+ highlighted = this.items[ i ] === item;
+ if ( this.items[ i ].isHighlighted() !== highlighted ) {
+ this.items[ i ].setHighlighted( highlighted );
changed = true;
}
}
@@ -10552,7 +15291,24 @@ OO.ui.SelectWidget.prototype.highlightItem = function ( item ) {
};
/**
- * Select an item.
+ * Programmatically select an option by its data. If the `data` parameter is omitted,
+ * or if the item does not exist, all options will be deselected.
+ *
+ * @param {Object|string} [data] Value of the item to select, omit to deselect all
+ * @fires select
+ * @chainable
+ */
+OO.ui.SelectWidget.prototype.selectItemByData = function ( data ) {
+ var itemFromData = this.getItemFromData( data );
+ if ( data === undefined || !itemFromData ) {
+ return this.selectItem();
+ }
+ return this.selectItem( itemFromData );
+};
+
+/**
+ * Programmatically select an option by its reference. If the `item` parameter is omitted,
+ * all options will be deselected.
*
* @param {OO.ui.OptionWidget} [item] Item to select, omit to deselect all
* @fires select
@@ -10563,9 +15319,9 @@ OO.ui.SelectWidget.prototype.selectItem = function ( item ) {
changed = false;
for ( i = 0, len = this.items.length; i < len; i++ ) {
- selected = this.items[i] === item;
- if ( this.items[i].isSelected() !== selected ) {
- this.items[i].setSelected( selected );
+ selected = this.items[ i ] === item;
+ if ( this.items[ i ].isSelected() !== selected ) {
+ this.items[ i ].setSelected( selected );
changed = true;
}
}
@@ -10579,6 +15335,10 @@ OO.ui.SelectWidget.prototype.selectItem = function ( item ) {
/**
* Press an item.
*
+ * Press is a state that occurs when a user mouses down on an item, but has not
+ * yet let go of the mouse. The item may appear selected, but it will not be selected until the user
+ * releases the mouse.
+ *
* @param {OO.ui.OptionWidget} [item] Item to press, omit to depress all
* @fires press
* @chainable
@@ -10588,9 +15348,9 @@ OO.ui.SelectWidget.prototype.pressItem = function ( item ) {
changed = false;
for ( i = 0, len = this.items.length; i < len; i++ ) {
- pressed = this.items[i] === item;
- if ( this.items[i].isPressed() !== pressed ) {
- this.items[i].setPressed( pressed );
+ pressed = this.items[ i ] === item;
+ if ( this.items[ i ].isPressed() !== pressed ) {
+ this.items[ i ].setPressed( pressed );
changed = true;
}
}
@@ -10604,8 +15364,12 @@ OO.ui.SelectWidget.prototype.pressItem = function ( item ) {
/**
* Choose an item.
*
- * Identical to #selectItem, but may vary in subclasses that want to take additional action when
- * an item is selected using the keyboard or mouse.
+ * Note that ‘choose’ should never be modified programmatically. A user can choose
+ * an option with the keyboard or mouse and it becomes selected. To select an item programmatically,
+ * use the #selectItem method.
+ *
+ * This method is identical to #selectItem, but may vary in subclasses that take additional action
+ * when users choose an item with the keyboard or mouse.
*
* @param {OO.ui.OptionWidget} item Item to choose
* @fires choose
@@ -10619,48 +15383,50 @@ OO.ui.SelectWidget.prototype.chooseItem = function ( item ) {
};
/**
- * Get an item relative to another one.
+ * Get an option by its position relative to the specified item (or to the start of the option array,
+ * if item is `null`). The direction in which to search through the option array is specified with a
+ * number: -1 for reverse (the default) or 1 for forward. The method will return an option, or
+ * `null` if there are no options in the array.
*
- * @param {OO.ui.OptionWidget} item Item to start at
- * @param {number} direction Direction to move in
- * @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the menu
+ * @param {OO.ui.OptionWidget|null} item Item to describe the start position, or `null` to start at the beginning of the array.
+ * @param {number} direction Direction to move in: -1 to move backward, 1 to move forward
+ * @return {OO.ui.OptionWidget|null} Item at position, `null` if there are no items in the select
*/
OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direction ) {
- var inc = direction > 0 ? 1 : -1,
- len = this.items.length,
- index = item instanceof OO.ui.OptionWidget ?
- $.inArray( item, this.items ) : ( 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];
+ var currentIndex, nextIndex, i,
+ increase = direction > 0 ? 1 : -1,
+ len = this.items.length;
+
+ if ( item instanceof OO.ui.OptionWidget ) {
+ currentIndex = $.inArray( item, this.items );
+ nextIndex = ( currentIndex + increase + len ) % len;
+ } else {
+ // If no item is selected and moving forward, start at the beginning.
+ // If moving backward, start at the end.
+ nextIndex = direction > 0 ? 0 : len - 1;
+ }
+
+ for ( i = 0; i < len; i++ ) {
+ item = this.items[ nextIndex ];
if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
return item;
}
- // Stop iterating when we've looped all the way around
- if ( i === stopAt ) {
- break;
- }
+ nextIndex = ( nextIndex + increase + len ) % len;
}
return null;
};
/**
- * Get the next selectable item.
+ * Get the next selectable item or `null` if there are no selectable items.
+ * Disabled options and menu-section markers and breaks are not selectable.
*
- * @return {OO.ui.OptionWidget|null} Item, `null` if ther aren't any selectable items
+ * @return {OO.ui.OptionWidget|null} Item, `null` if there 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];
+ item = this.items[ i ];
if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
return item;
}
@@ -10670,10 +15436,8 @@ OO.ui.SelectWidget.prototype.getFirstSelectableItem = function () {
};
/**
- * 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.
+ * Add an array of options to the select. Optionally, an index number can be used to
+ * specify an insertion point.
*
* @param {OO.ui.OptionWidget[]} items Items to add
* @param {number} [index] Index to insert items after
@@ -10681,22 +15445,6 @@ OO.ui.SelectWidget.prototype.getFirstSelectableItem = function () {
* @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 );
- }
-
// Mixin method
OO.ui.GroupWidget.prototype.addItems.call( this, items, index );
@@ -10707,24 +15455,20 @@ OO.ui.SelectWidget.prototype.addItems = function ( items, index ) {
};
/**
- * Remove items.
- *
- * Items will be detached, not removed, so they can be used later.
+ * Remove the specified array of options from the select. Options will be detached
+ * from the DOM, not removed, so they can be reused later. To remove all options from
+ * the select, you may wish to use the #clearItems method instead.
*
* @param {OO.ui.OptionWidget[]} items Items to remove
* @fires remove
* @chainable
*/
OO.ui.SelectWidget.prototype.removeItems = function ( items ) {
- var i, len, item, hash;
+ var i, len, item;
+ // Deselect items being removed
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];
- }
+ item = items[ i ];
if ( item.isSelected() ) {
this.selectItem( null );
}
@@ -10739,9 +15483,9 @@ OO.ui.SelectWidget.prototype.removeItems = function ( items ) {
};
/**
- * Clear all items.
- *
- * Items will be detached, not removed, so they can be used later.
+ * Clear all options from the select. Options will be detached from the DOM, not removed,
+ * so that they can be reused later. To remove a subset of options from the select, use
+ * the #removeItems method.
*
* @fires remove
* @chainable
@@ -10749,10 +15493,10 @@ OO.ui.SelectWidget.prototype.removeItems = function ( items ) {
OO.ui.SelectWidget.prototype.clearItems = function () {
var items = this.items.slice();
- // Clear all items
- this.hashes = {};
// Mixin method
OO.ui.GroupWidget.prototype.clearItems.call( this );
+
+ // Clear selection
this.selectItem( null );
this.emit( 'remove', items );
@@ -10761,12 +15505,42 @@ OO.ui.SelectWidget.prototype.clearItems = function () {
};
/**
- * Select widget containing button options.
+ * ButtonSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains
+ * button options and is used together with
+ * OO.ui.ButtonOptionWidget. The ButtonSelectWidget provides an interface for
+ * highlighting, choosing, and selecting mutually exclusive options. Please see
+ * the [OOjs UI documentation on MediaWiki] [1] for more information.
*
- * Use together with OO.ui.ButtonOptionWidget.
+ * @example
+ * // Example: A ButtonSelectWidget that contains three ButtonOptionWidgets
+ * var option1 = new OO.ui.ButtonOptionWidget( {
+ * data: 1,
+ * label: 'Option 1',
+ * title: 'Button option 1'
+ * } );
+ *
+ * var option2 = new OO.ui.ButtonOptionWidget( {
+ * data: 2,
+ * label: 'Option 2',
+ * title: 'Button option 2'
+ * } );
+ *
+ * var option3 = new OO.ui.ButtonOptionWidget( {
+ * data: 3,
+ * label: 'Option 3',
+ * title: 'Button option 3'
+ * } );
+ *
+ * var buttonSelect=new OO.ui.ButtonSelectWidget( {
+ * items: [ option1, option2, option3 ]
+ * } );
+ * $( 'body' ).append( buttonSelect.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
*
* @class
* @extends OO.ui.SelectWidget
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -10775,6 +15549,15 @@ OO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {
// Parent constructor
OO.ui.ButtonSelectWidget.super.call( this, config );
+ // Mixin constructors
+ OO.ui.TabIndexedElement.call( this, config );
+
+ // Events
+ this.$element.on( {
+ focus: this.bindKeyDownListener.bind( this ),
+ blur: this.unbindKeyDownListener.bind( this )
+ } );
+
// Initialization
this.$element.addClass( 'oo-ui-buttonSelectWidget' );
};
@@ -10782,179 +15565,232 @@ OO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.ButtonSelectWidget, OO.ui.SelectWidget );
+OO.mixinClass( OO.ui.ButtonSelectWidget, OO.ui.TabIndexedElement );
/**
- * Overlaid menu of options.
+ * RadioSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains radio
+ * options and is used together with OO.ui.RadioOptionWidget. The RadioSelectWidget provides
+ * an interface for adding, removing and selecting options.
+ * Please see the [OOjs UI documentation on MediaWiki][1] for more information.
+ *
+ * @example
+ * // A RadioSelectWidget with RadioOptions.
+ * var option1 = new OO.ui.RadioOptionWidget( {
+ * data: 'a',
+ * label: 'Selected radio option'
+ * } );
*
- * Menus are clipped to the visible viewport. They do not provide a control for opening or closing
- * the menu.
+ * var option2 = new OO.ui.RadioOptionWidget( {
+ * data: 'b',
+ * label: 'Unselected radio option'
+ * } );
*
- * Use together with OO.ui.MenuItemWidget.
+ * var radioSelect=new OO.ui.RadioSelectWidget( {
+ * items: [ option1, option2 ]
+ * } );
+ *
+ * // Select 'option 1' using the RadioSelectWidget's selectItem() method.
+ * radioSelect.selectItem( option1 );
+ *
+ * $( 'body' ).append( radioSelect.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
+
*
* @class
* @extends OO.ui.SelectWidget
- * @mixins OO.ui.ClippableElement
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {OO.ui.InputWidget} [input] Input to bind keyboard handlers to
- * @cfg {OO.ui.Widget} [widget] Widget to bind mouse handlers to
- * @cfg {boolean} [autoHide=true] Hide the menu when the mouse is pressed outside the menu
*/
-OO.ui.MenuWidget = function OoUiMenuWidget( config ) {
- // Config intialization
+OO.ui.RadioSelectWidget = function OoUiRadioSelectWidget( config ) {
+ // Parent constructor
+ OO.ui.RadioSelectWidget.super.call( this, config );
+
+ // Mixin constructors
+ OO.ui.TabIndexedElement.call( this, config );
+
+ // Events
+ this.$element.on( {
+ focus: this.bindKeyDownListener.bind( this ),
+ blur: this.unbindKeyDownListener.bind( this )
+ } );
+
+ // Initialization
+ this.$element.addClass( 'oo-ui-radioSelectWidget' );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.RadioSelectWidget, OO.ui.SelectWidget );
+OO.mixinClass( OO.ui.RadioSelectWidget, OO.ui.TabIndexedElement );
+
+/**
+ * MenuSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains options and
+ * is used together with OO.ui.MenuOptionWidget. It is designed be used as part of another widget.
+ * See {@link OO.ui.DropdownWidget DropdownWidget}, {@link OO.ui.ComboBoxWidget ComboBoxWidget},
+ * and {@link OO.ui.LookupElement LookupElement} for examples of widgets that contain menus.
+ * MenuSelectWidgets themselves are not instantiated directly, rather subclassed
+ * and customized to be opened, closed, and displayed as needed.
+ *
+ * By default, menus are clipped to the visible viewport and are not visible when a user presses the
+ * mouse outside the menu.
+ *
+ * Menus also have support for keyboard interaction:
+ *
+ * - Enter/Return key: choose and select a menu option
+ * - Up-arrow key: highlight the previous menu option
+ * - Down-arrow key: highlight the next menu option
+ * - Esc key: hide the menu
+ *
+ * Please see the [OOjs UI documentation on MediaWiki][1] for more information.
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options
+ *
+ * @class
+ * @extends OO.ui.SelectWidget
+ * @mixins OO.ui.ClippableElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {OO.ui.TextInputWidget} [input] Text input used to implement option highlighting for menu items that match
+ * the text the user types. This config is used by {@link OO.ui.ComboBoxWidget ComboBoxWidget}
+ * and {@link OO.ui.LookupElement LookupElement}
+ * @cfg {OO.ui.Widget} [widget] Widget associated with the menu’s active state. If the user clicks the mouse
+ * anywhere on the page outside of this widget, the menu is hidden.
+ * @cfg {boolean} [autoHide=true] Hide the menu when the mouse is pressed outside the menu.
+ */
+OO.ui.MenuSelectWidget = function OoUiMenuSelectWidget( config ) {
+ // Configuration initialization
config = config || {};
// Parent constructor
- OO.ui.MenuWidget.super.call( this, config );
+ OO.ui.MenuSelectWidget.super.call( this, config );
// Mixin constructors
OO.ui.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$group } ) );
// Properties
- this.flashing = false;
- this.visible = false;
this.newItems = null;
this.autoHide = config.autoHide === undefined || !!config.autoHide;
this.$input = config.input ? config.input.$input : null;
this.$widget = config.widget ? config.widget.$element : null;
- this.$previousFocus = null;
- this.isolated = !config.input;
- this.onKeyDownHandler = OO.ui.bind( this.onKeyDown, this );
- this.onDocumentMouseDownHandler = OO.ui.bind( this.onDocumentMouseDown, this );
+ this.onDocumentMouseDownHandler = this.onDocumentMouseDown.bind( this );
// Initialization
this.$element
- .hide()
- .attr( 'role', 'menu' )
- .addClass( 'oo-ui-menuWidget' );
+ .addClass( 'oo-ui-menuSelectWidget' )
+ .attr( 'role', 'menu' );
+
+ // Initially hidden - using #toggle may cause errors if subclasses override toggle with methods
+ // that reference properties not initialized at that time of parent class construction
+ // TODO: Find a better way to handle post-constructor setup
+ this.visible = false;
+ this.$element.addClass( 'oo-ui-element-hidden' );
};
/* Setup */
-OO.inheritClass( OO.ui.MenuWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.MenuWidget, OO.ui.ClippableElement );
+OO.inheritClass( OO.ui.MenuSelectWidget, OO.ui.SelectWidget );
+OO.mixinClass( OO.ui.MenuSelectWidget, OO.ui.ClippableElement );
/* Methods */
/**
* Handles document mouse down events.
*
+ * @protected
* @param {jQuery.Event} e Key down event
*/
-OO.ui.MenuWidget.prototype.onDocumentMouseDown = function ( e ) {
- if ( !$.contains( this.$element[0], e.target ) && ( !this.$widget || !$.contains( this.$widget[0], e.target ) ) ) {
+OO.ui.MenuSelectWidget.prototype.onDocumentMouseDown = function ( e ) {
+ if (
+ !OO.ui.contains( this.$element[ 0 ], e.target, true ) &&
+ ( !this.$widget || !OO.ui.contains( this.$widget[ 0 ], e.target, true ) )
+ ) {
this.toggle( false );
}
};
/**
- * Handles key down events.
- *
- * @param {jQuery.Event} e Key down event
+ * @inheritdoc
*/
-OO.ui.MenuWidget.prototype.onKeyDown = function ( e ) {
- var nextItem,
- handled = false,
- highlightItem = this.getHighlightedItem();
+OO.ui.MenuSelectWidget.prototype.onKeyDown = function ( e ) {
+ var currentItem = this.getHighlightedItem() || this.getSelectedItem();
if ( !this.isDisabled() && this.isVisible() ) {
- if ( !highlightItem ) {
- highlightItem = this.getSelectedItem();
- }
switch ( e.keyCode ) {
- case OO.ui.Keys.ENTER:
- this.chooseItem( 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;
+ case OO.ui.Keys.LEFT:
+ case OO.ui.Keys.RIGHT:
+ // Do nothing if a text field is associated, arrow keys will be handled natively
+ if ( !this.$input ) {
+ OO.ui.MenuSelectWidget.super.prototype.onKeyDown.call( this, e );
+ }
break;
case OO.ui.Keys.ESCAPE:
- if ( highlightItem ) {
- highlightItem.setHighlighted( false );
+ case OO.ui.Keys.TAB:
+ if ( currentItem ) {
+ currentItem.setHighlighted( false );
}
this.toggle( false );
- handled = true;
+ // Don't prevent tabbing away, prevent defocusing
+ if ( e.keyCode === OO.ui.Keys.ESCAPE ) {
+ e.preventDefault();
+ e.stopPropagation();
+ }
break;
- }
-
- if ( nextItem ) {
- this.highlightItem( nextItem );
- nextItem.scrollElementIntoView();
- }
-
- if ( handled ) {
- e.preventDefault();
- e.stopPropagation();
- return false;
+ default:
+ OO.ui.MenuSelectWidget.super.prototype.onKeyDown.call( this, e );
+ return;
}
}
};
/**
- * Bind key down listener.
+ * @inheritdoc
*/
-OO.ui.MenuWidget.prototype.bindKeyDownListener = function () {
+OO.ui.MenuSelectWidget.prototype.bindKeyDownListener = function () {
if ( this.$input ) {
this.$input.on( 'keydown', this.onKeyDownHandler );
} else {
- // Capture menu navigation keys
- this.getElementWindow().addEventListener( 'keydown', this.onKeyDownHandler, true );
+ OO.ui.MenuSelectWidget.super.prototype.bindKeyDownListener.call( this );
}
};
/**
- * Unbind key down listener.
+ * @inheritdoc
*/
-OO.ui.MenuWidget.prototype.unbindKeyDownListener = function () {
+OO.ui.MenuSelectWidget.prototype.unbindKeyDownListener = function () {
if ( this.$input ) {
- this.$input.off( 'keydown' );
+ this.$input.off( 'keydown', this.onKeyDownHandler );
} else {
- this.getElementWindow().removeEventListener( 'keydown', this.onKeyDownHandler, true );
+ OO.ui.MenuSelectWidget.super.prototype.unbindKeyDownListener.call( this );
}
};
/**
* Choose an item.
*
- * This will close the menu when done, unlike selectItem which only changes selection.
+ * When a user chooses an item, the menu is closed.
*
+ * Note that ‘choose’ should never be modified programmatically. A user can choose an option with the keyboard
+ * or mouse and it becomes selected. To select an item programmatically, use the #selectItem method.
* @param {OO.ui.OptionWidget} item Item to choose
* @chainable
*/
-OO.ui.MenuWidget.prototype.chooseItem = function ( item ) {
- var widget = this;
-
- // Parent method
- OO.ui.MenuWidget.super.prototype.chooseItem.call( this, item );
-
- if ( item && !this.flashing ) {
- this.flashing = true;
- item.flash().done( function () {
- widget.toggle( false );
- widget.flashing = false;
- } );
- } else {
- this.toggle( false );
- }
-
+OO.ui.MenuSelectWidget.prototype.chooseItem = function ( item ) {
+ OO.ui.MenuSelectWidget.super.prototype.chooseItem.call( this, item );
+ this.toggle( false );
return this;
};
/**
* @inheritdoc
*/
-OO.ui.MenuWidget.prototype.addItems = function ( items, index ) {
+OO.ui.MenuSelectWidget.prototype.addItems = function ( items, index ) {
var i, len, item;
// Parent method
- OO.ui.MenuWidget.super.prototype.addItems.call( this, items, index );
+ OO.ui.MenuSelectWidget.super.prototype.addItems.call( this, items, index );
// Auto-initialize
if ( !this.newItems ) {
@@ -10962,7 +15798,7 @@ OO.ui.MenuWidget.prototype.addItems = function ( items, index ) {
}
for ( i = 0, len = items.length; i < len; i++ ) {
- item = items[i];
+ item = items[ i ];
if ( this.isVisible() ) {
// Defer fitting label until item has been attached
item.fitLabel();
@@ -10980,9 +15816,9 @@ OO.ui.MenuWidget.prototype.addItems = function ( items, index ) {
/**
* @inheritdoc
*/
-OO.ui.MenuWidget.prototype.removeItems = function ( items ) {
+OO.ui.MenuSelectWidget.prototype.removeItems = function ( items ) {
// Parent method
- OO.ui.MenuWidget.super.prototype.removeItems.call( this, items );
+ OO.ui.MenuSelectWidget.super.prototype.removeItems.call( this, items );
// Reevaluate clipping
this.clip();
@@ -10993,9 +15829,9 @@ OO.ui.MenuWidget.prototype.removeItems = function ( items ) {
/**
* @inheritdoc
*/
-OO.ui.MenuWidget.prototype.clearItems = function () {
+OO.ui.MenuSelectWidget.prototype.clearItems = function () {
// Parent method
- OO.ui.MenuWidget.super.prototype.clearItems.call( this );
+ OO.ui.MenuSelectWidget.super.prototype.clearItems.call( this );
// Reevaluate clipping
this.clip();
@@ -11006,27 +15842,22 @@ OO.ui.MenuWidget.prototype.clearItems = function () {
/**
* @inheritdoc
*/
-OO.ui.MenuWidget.prototype.toggle = function ( visible ) {
+OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
visible = ( visible === undefined ? !this.visible : !!visible ) && !!this.items.length;
var i, len,
change = visible !== this.isVisible();
// Parent method
- OO.ui.MenuWidget.super.prototype.toggle.call( this, visible );
+ OO.ui.MenuSelectWidget.super.prototype.toggle.call( this, visible );
if ( change ) {
if ( visible ) {
this.bindKeyDownListener();
- // Change focus to enable keyboard navigation
- if ( this.isolated && this.$input && !this.$input.is( ':focus' ) ) {
- this.$previousFocus = this.$( ':focus' );
- this.$input[0].focus();
- }
if ( this.newItems && this.newItems.length ) {
for ( i = 0, len = this.newItems.length; i < len; i++ ) {
- this.newItems[i].fitLabel();
+ this.newItems[ i ].fitLabel();
}
this.newItems = null;
}
@@ -11040,10 +15871,6 @@ OO.ui.MenuWidget.prototype.toggle = function ( visible ) {
}
} else {
this.unbindKeyDownListener();
- if ( this.isolated && this.$previousFocus ) {
- this.$previousFocus[0].focus();
- this.$previousFocus = null;
- }
this.getElementDocument().removeEventListener(
'mousedown', this.onDocumentMouseDownHandler, true
);
@@ -11055,53 +15882,62 @@ OO.ui.MenuWidget.prototype.toggle = function ( visible ) {
};
/**
- * Menu for a text input widget.
- *
- * This menu is specially designed to be positioned beneath the text input widget. Even if the input
- * is in a different frame, the menu's position is automatically calulated and maintained when the
- * menu is toggled or the window is resized.
+ * TextInputMenuSelectWidget is a menu that is specially designed to be positioned beneath
+ * a {@link OO.ui.TextInputWidget text input} field. The menu's position is automatically
+ * calculated and maintained when the menu is toggled or the window is resized.
+ * See OO.ui.ComboBoxWidget for an example of a widget that uses this class.
*
* @class
- * @extends OO.ui.MenuWidget
+ * @extends OO.ui.MenuSelectWidget
*
* @constructor
- * @param {OO.ui.TextInputWidget} input Text input widget to provide menu for
+ * @param {OO.ui.TextInputWidget} inputWidget 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 ) {
+OO.ui.TextInputMenuSelectWidget = function OoUiTextInputMenuSelectWidget( inputWidget, config ) {
+ // Allow passing positional parameters inside the config object
+ if ( OO.isPlainObject( inputWidget ) && config === undefined ) {
+ config = inputWidget;
+ inputWidget = config.inputWidget;
+ }
+
+ // Configuration initialization
+ config = config || {};
+
// Parent constructor
- OO.ui.TextInputMenuWidget.super.call( this, config );
+ OO.ui.TextInputMenuSelectWidget.super.call( this, config );
// Properties
- this.input = input;
- this.$container = config.$container || this.input.$element;
- this.onWindowResizeHandler = OO.ui.bind( this.onWindowResize, this );
+ this.inputWidget = inputWidget;
+ this.$container = config.$container || this.inputWidget.$element;
+ this.onWindowResizeHandler = this.onWindowResize.bind( this );
// Initialization
- this.$element.addClass( 'oo-ui-textInputMenuWidget' );
+ this.$element.addClass( 'oo-ui-textInputMenuSelectWidget' );
};
/* Setup */
-OO.inheritClass( OO.ui.TextInputMenuWidget, OO.ui.MenuWidget );
+OO.inheritClass( OO.ui.TextInputMenuSelectWidget, OO.ui.MenuSelectWidget );
/* Methods */
/**
* Handle window resize event.
*
+ * @private
* @param {jQuery.Event} e Window resize event
*/
-OO.ui.TextInputMenuWidget.prototype.onWindowResize = function () {
+OO.ui.TextInputMenuSelectWidget.prototype.onWindowResize = function () {
this.position();
};
/**
* @inheritdoc
*/
-OO.ui.TextInputMenuWidget.prototype.toggle = function ( visible ) {
- visible = !!visible;
+OO.ui.TextInputMenuSelectWidget.prototype.toggle = function ( visible ) {
+ visible = visible === undefined ? !this.isVisible() : !!visible;
var change = visible !== this.isVisible();
@@ -11113,14 +15949,14 @@ OO.ui.TextInputMenuWidget.prototype.toggle = function ( visible ) {
}
// Parent method
- OO.ui.TextInputMenuWidget.super.prototype.toggle.call( this, visible );
+ OO.ui.TextInputMenuSelectWidget.super.prototype.toggle.call( this, visible );
if ( change ) {
if ( this.isVisible() ) {
this.position();
- this.$( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
+ $( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
} else {
- this.$( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
+ $( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
}
}
@@ -11130,33 +15966,18 @@ OO.ui.TextInputMenuWidget.prototype.toggle = function ( visible ) {
/**
* Position the menu.
*
+ * @private
* @chainable
*/
-OO.ui.TextInputMenuWidget.prototype.position = function () {
- var frameOffset,
- $container = this.$container,
- dimensions = $container.offset();
+OO.ui.TextInputMenuSelectWidget.prototype.position = function () {
+ var $container = this.$container,
+ pos = OO.ui.Element.static.getRelativePosition( $container, this.$element.offsetParent() );
// Position under input
- dimensions.top += $container.height();
+ pos.top += $container.height();
+ this.$element.css( pos );
- // Compensate for frame position if in a differnt frame
- if ( this.input.$.$iframe && this.input.$.context !== this.$element[0].ownerDocument ) {
- frameOffset = OO.ui.Element.getRelativePosition(
- this.input.$.$iframe, 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 -
- $container.width() - dimensions.left;
- // Erase the value for 'left':
- delete dimensions.left;
- }
- }
- this.$element.css( dimensions );
+ // Set width
this.setIdealSize( $container.width() );
// We updated the position, so re-evaluate the clipping state
this.clip();
@@ -11165,83 +15986,165 @@ OO.ui.TextInputMenuWidget.prototype.position = function () {
};
/**
- * Structured list of items.
+ * OutlineSelectWidget is a structured list that contains {@link OO.ui.OutlineOptionWidget outline options}
+ * A set of controls can be provided with an {@link OO.ui.OutlineControlsWidget outline controls} widget.
*
- * Use with OO.ui.OutlineItemWidget.
+ * ####Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.####
*
* @class
* @extends OO.ui.SelectWidget
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
-OO.ui.OutlineWidget = function OoUiOutlineWidget( config ) {
- // Config intialization
- config = config || {};
+OO.ui.OutlineSelectWidget = function OoUiOutlineSelectWidget( config ) {
+ // Parent constructor
+ OO.ui.OutlineSelectWidget.super.call( this, config );
+
+ // Mixin constructors
+ OO.ui.TabIndexedElement.call( this, config );
+
+ // Events
+ this.$element.on( {
+ focus: this.bindKeyDownListener.bind( this ),
+ blur: this.unbindKeyDownListener.bind( this )
+ } );
+
+ // Initialization
+ this.$element.addClass( 'oo-ui-outlineSelectWidget' );
+};
+
+/* Setup */
+OO.inheritClass( OO.ui.OutlineSelectWidget, OO.ui.SelectWidget );
+OO.mixinClass( OO.ui.OutlineSelectWidget, OO.ui.TabIndexedElement );
+
+/**
+ * TabSelectWidget is a list that contains {@link OO.ui.TabOptionWidget tab options}
+ *
+ * ####Currently, this class is only used by {@link OO.ui.IndexLayout index layouts}.####
+ *
+ * @class
+ * @extends OO.ui.SelectWidget
+ * @mixins OO.ui.TabIndexedElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.TabSelectWidget = function OoUiTabSelectWidget( config ) {
// Parent constructor
- OO.ui.OutlineWidget.super.call( this, config );
+ OO.ui.TabSelectWidget.super.call( this, config );
+
+ // Mixin constructors
+ OO.ui.TabIndexedElement.call( this, config );
+
+ // Events
+ this.$element.on( {
+ focus: this.bindKeyDownListener.bind( this ),
+ blur: this.unbindKeyDownListener.bind( this )
+ } );
// Initialization
- this.$element.addClass( 'oo-ui-outlineWidget' );
+ this.$element.addClass( 'oo-ui-tabSelectWidget' );
};
/* Setup */
-OO.inheritClass( OO.ui.OutlineWidget, OO.ui.SelectWidget );
+OO.inheritClass( OO.ui.TabSelectWidget, OO.ui.SelectWidget );
+OO.mixinClass( OO.ui.TabSelectWidget, OO.ui.TabIndexedElement );
/**
- * Switch that slides on and off.
+ * ToggleSwitches are switches that slide on and off. Their state is represented by a Boolean
+ * value (`true` for ‘on’, and `false` otherwise, the default). The ‘off’ state is represented
+ * visually by a slider in the leftmost position.
+ *
+ * @example
+ * // Toggle switches in the 'off' and 'on' position.
+ * var toggleSwitch1 = new OO.ui.ToggleSwitchWidget();
+ * var toggleSwitch2 = new OO.ui.ToggleSwitchWidget( {
+ * value: true
+ * } );
+ *
+ * // Create a FieldsetLayout to layout and label switches
+ * var fieldset = new OO.ui.FieldsetLayout( {
+ * label: 'Toggle switches'
+ * } );
+ * fieldset.addItems( [
+ * new OO.ui.FieldLayout( toggleSwitch1, { label: 'Off', align: 'top' } ),
+ * new OO.ui.FieldLayout( toggleSwitch2, { label: 'On', align: 'top' } )
+ * ] );
+ * $( 'body' ).append( fieldset.$element );
*
* @class
- * @extends OO.ui.Widget
- * @mixins OO.ui.ToggleWidget
+ * @extends OO.ui.ToggleWidget
+ * @mixins OO.ui.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {boolean} [value=false] Initial value
+ * @cfg {boolean} [value=false] The toggle switch’s initial on/off state.
+ * By default, the toggle switch is in the 'off' position.
*/
OO.ui.ToggleSwitchWidget = function OoUiToggleSwitchWidget( config ) {
// Parent constructor
OO.ui.ToggleSwitchWidget.super.call( this, config );
// Mixin constructors
- OO.ui.ToggleWidget.call( this, config );
+ OO.ui.TabIndexedElement.call( this, config );
// Properties
this.dragging = false;
this.dragStart = null;
this.sliding = false;
- this.$glow = this.$( '<span>' );
- this.$grip = this.$( '<span>' );
+ this.$glow = $( '<span>' );
+ this.$grip = $( '<span>' );
// Events
- this.$element.on( 'click', OO.ui.bind( this.onClick, this ) );
+ this.$element.on( {
+ click: this.onClick.bind( this ),
+ keypress: this.onKeyPress.bind( this )
+ } );
// Initialization
this.$glow.addClass( 'oo-ui-toggleSwitchWidget-glow' );
this.$grip.addClass( 'oo-ui-toggleSwitchWidget-grip' );
this.$element
.addClass( 'oo-ui-toggleSwitchWidget' )
+ .attr( 'role', 'checkbox' )
.append( this.$glow, this.$grip );
};
/* Setup */
-OO.inheritClass( OO.ui.ToggleSwitchWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.ToggleSwitchWidget, OO.ui.ToggleWidget );
+OO.inheritClass( OO.ui.ToggleSwitchWidget, OO.ui.ToggleWidget );
+OO.mixinClass( OO.ui.ToggleSwitchWidget, OO.ui.TabIndexedElement );
/* Methods */
/**
- * Handle mouse down events.
+ * Handle mouse click events.
*
- * @param {jQuery.Event} e Mouse down event
+ * @private
+ * @param {jQuery.Event} e Mouse click event
*/
OO.ui.ToggleSwitchWidget.prototype.onClick = function ( e ) {
if ( !this.isDisabled() && e.which === 1 ) {
this.setValue( !this.value );
}
+ return false;
+};
+
+/**
+ * Handle key press events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key press event
+ */
+OO.ui.ToggleSwitchWidget.prototype.onKeyPress = function ( e ) {
+ if ( !this.isDisabled() && ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER ) ) {
+ this.setValue( !this.value );
+ return false;
+ }
};
}( OO ) );
diff --git a/resources/lib/oojs-ui/oojs-ui.rtl.css b/resources/lib/oojs-ui/oojs-ui.rtl.css
deleted file mode 100644
index 7f1fa344..00000000
--- a/resources/lib/oojs-ui/oojs-ui.rtl.css
+++ /dev/null
@@ -1,112 +0,0 @@
-/*!
- * OOjs UI v0.1.0
- * 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: 2014-09-11T19:39:50Z
- */
-/*
- * Blank theme mixins.
- *
- * Base styles invoke these mixins at the end of their definitions. Override these mixins to add
- * additional rules to the base styles.
- */
-.oo-ui-icon-add-item {
- background-image: /* @embed */ url(images/icons/add-item.png);
-}
-.oo-ui-icon-advanced {
- background-image: /* @embed */ url(images/icons/advanced.png);
-}
-.oo-ui-icon-alert {
- background-image: /* @embed */ url(images/icons/alert.png);
-}
-.oo-ui-icon-check {
- background-image: /* @embed */ url(images/icons/check.png);
-}
-.oo-ui-icon-clear {
- background-image: /* @embed */ url(images/icons/clear.png);
-}
-.oo-ui-icon-close {
- background-image: /* @embed */ url(images/icons/close.png);
-}
-.oo-ui-icon-code {
- background-image: /* @embed */ url(images/icons/code.png);
-}
-.oo-ui-icon-collapse {
- background-image: /* @embed */ url(images/icons/collapse.png);
-}
-.oo-ui-icon-comment {
- background-image: /* @embed */ url(images/icons/comment.png);
-}
-.oo-ui-icon-expand {
- background-image: /* @embed */ url(images/icons/expand.png);
-}
-.oo-ui-icon-help {
- background-image: /* @embed */ url(images/icons/help.png);
-}
-.oo-ui-icon-info {
- background-image: /* @embed */ url(images/icons/info.png);
-}
-.oo-ui-icon-link {
- background-image: /* @embed */ url(images/icons/link.png);
-}
-.oo-ui-icon-menu {
- background-image: /* @embed */ url(images/icons/menu.png);
-}
-.oo-ui-icon-next {
- background-image: /* @embed */ url(images/icons/move-rtl.png);
-}
-.oo-ui-icon-picture {
- background-image: /* @embed */ url(images/icons/picture.png);
-}
-.oo-ui-icon-previous {
- background-image: /* @embed */ url(images/icons/move-ltr.png);
-}
-.oo-ui-icon-redo {
- background-image: /* @embed */ url(images/icons/arched-arrow-rtl.png);
-}
-.oo-ui-icon-remove {
- background-image: /* @embed */ url(images/icons/remove.png);
-}
-.oo-ui-icon-search {
- background-image: /* @embed */ url(images/icons/search.png);
-}
-.oo-ui-icon-settings {
- background-image: /* @embed */ url(images/icons/settings.png);
-}
-.oo-ui-icon-tag {
- background-image: /* @embed */ url(images/icons/tag.png);
-}
-.oo-ui-icon-undo {
- background-image: /* @embed */ url(images/icons/arched-arrow-ltr.png);
-}
-.oo-ui-icon-window {
- background-image: /* @embed */ url(images/icons/window.png);
-}
-.oo-ui-indicator-alert {
- background-image: /* @embed */ url(images/indicators/alert.png);
-}
-.oo-ui-indicator-down {
- background-image: /* @embed */ url(images/indicators/arrow-down.png);
-}
-.oo-ui-indicator-next {
- background-image: /* @embed */ url(images/indicators/arrow-rtl.png);
-}
-.oo-ui-indicator-previous {
- background-image: /* @embed */ url(images/indicators/arrow-ltr.png);
-}
-.oo-ui-indicator-required {
- background-image: /* @embed */ url(images/indicators/required.png);
-}
-.oo-ui-indicator-up {
- background-image: /* @embed */ url(images/indicators/arrow-up.png);
-}
-.oo-ui-texture-pending {
- background-image: /* @embed */ url(images/textures/pending.gif);
-}
-.oo-ui-texture-transparency {
- background-image: /* @embed */ url(images/textures/transparency.png);
-}
diff --git a/resources/lib/oojs-ui/oojs-ui.svg.css b/resources/lib/oojs-ui/oojs-ui.svg.css
deleted file mode 100644
index aafdff36..00000000
--- a/resources/lib/oojs-ui/oojs-ui.svg.css
+++ /dev/null
@@ -1,112 +0,0 @@
-/*!
- * OOjs UI v0.1.0-pre (f2c3f12959)
- * 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: 2014-09-18T23:22:20Z
- */
-/*
- * Blank theme mixins.
- *
- * Base styles invoke these mixins at the end of their definitions. Override these mixins to add
- * additional rules to the base styles.
- */
-.oo-ui-icon-add-item {
- background-image: /* @embed */ url(images/icons/add-item.svg);
-}
-.oo-ui-icon-advanced {
- background-image: /* @embed */ url(images/icons/advanced.svg);
-}
-.oo-ui-icon-alert {
- background-image: /* @embed */ url(images/icons/alert.svg);
-}
-.oo-ui-icon-check {
- background-image: /* @embed */ url(images/icons/check.svg);
-}
-.oo-ui-icon-clear {
- background-image: /* @embed */ url(images/icons/clear.svg);
-}
-.oo-ui-icon-close {
- background-image: /* @embed */ url(images/icons/close.svg);
-}
-.oo-ui-icon-code {
- background-image: /* @embed */ url(images/icons/code.svg);
-}
-.oo-ui-icon-collapse {
- background-image: /* @embed */ url(images/icons/collapse.svg);
-}
-.oo-ui-icon-comment {
- background-image: /* @embed */ url(images/icons/comment.svg);
-}
-.oo-ui-icon-expand {
- background-image: /* @embed */ url(images/icons/expand.svg);
-}
-.oo-ui-icon-help {
- background-image: /* @embed */ url(images/icons/help.svg);
-}
-.oo-ui-icon-info {
- background-image: /* @embed */ url(images/icons/info.svg);
-}
-.oo-ui-icon-link {
- background-image: /* @embed */ url(images/icons/link.svg);
-}
-.oo-ui-icon-menu {
- background-image: /* @embed */ url(images/icons/menu.svg);
-}
-.oo-ui-icon-next {
- background-image: /* @embed */ url(images/icons/move-ltr.svg);
-}
-.oo-ui-icon-picture {
- background-image: /* @embed */ url(images/icons/picture.svg);
-}
-.oo-ui-icon-previous {
- background-image: /* @embed */ url(images/icons/move-rtl.svg);
-}
-.oo-ui-icon-redo {
- background-image: /* @embed */ url(images/icons/arched-arrow-ltr.svg);
-}
-.oo-ui-icon-remove {
- background-image: /* @embed */ url(images/icons/remove.svg);
-}
-.oo-ui-icon-search {
- background-image: /* @embed */ url(images/icons/search.svg);
-}
-.oo-ui-icon-settings {
- background-image: /* @embed */ url(images/icons/settings.svg);
-}
-.oo-ui-icon-tag {
- background-image: /* @embed */ url(images/icons/tag.svg);
-}
-.oo-ui-icon-undo {
- background-image: /* @embed */ url(images/icons/arched-arrow-rtl.svg);
-}
-.oo-ui-icon-window {
- background-image: /* @embed */ url(images/icons/window.svg);
-}
-.oo-ui-indicator-alert {
- background-image: /* @embed */ url(images/indicators/alert.svg);
-}
-.oo-ui-indicator-down {
- background-image: /* @embed */ url(images/indicators/arrow-down.svg);
-}
-.oo-ui-indicator-next {
- background-image: /* @embed */ url(images/indicators/arrow-ltr.svg);
-}
-.oo-ui-indicator-previous {
- background-image: /* @embed */ url(images/indicators/arrow-rtl.svg);
-}
-.oo-ui-indicator-required {
- background-image: /* @embed */ url(images/indicators/required.svg);
-}
-.oo-ui-indicator-up {
- background-image: /* @embed */ url(images/indicators/arrow-up.svg);
-}
-.oo-ui-texture-pending {
- background-image: /* @embed */ url(images/textures/pending.gif);
-}
-.oo-ui-texture-transparency {
- background-image: /* @embed */ url(images/textures/transparency.svg);
-}
diff --git a/resources/lib/oojs-ui/oojs-ui.svg.rtl.css b/resources/lib/oojs-ui/oojs-ui.svg.rtl.css
deleted file mode 100644
index 5a78d6b5..00000000
--- a/resources/lib/oojs-ui/oojs-ui.svg.rtl.css
+++ /dev/null
@@ -1,112 +0,0 @@
-/*!
- * OOjs UI v0.1.0
- * 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: 2014-09-11T19:39:50Z
- */
-/*
- * Blank theme mixins.
- *
- * Base styles invoke these mixins at the end of their definitions. Override these mixins to add
- * additional rules to the base styles.
- */
-.oo-ui-icon-add-item {
- background-image: /* @embed */ url(images/icons/add-item.svg);
-}
-.oo-ui-icon-advanced {
- background-image: /* @embed */ url(images/icons/advanced.svg);
-}
-.oo-ui-icon-alert {
- background-image: /* @embed */ url(images/icons/alert.svg);
-}
-.oo-ui-icon-check {
- background-image: /* @embed */ url(images/icons/check.svg);
-}
-.oo-ui-icon-clear {
- background-image: /* @embed */ url(images/icons/clear.svg);
-}
-.oo-ui-icon-close {
- background-image: /* @embed */ url(images/icons/close.svg);
-}
-.oo-ui-icon-code {
- background-image: /* @embed */ url(images/icons/code.svg);
-}
-.oo-ui-icon-collapse {
- background-image: /* @embed */ url(images/icons/collapse.svg);
-}
-.oo-ui-icon-comment {
- background-image: /* @embed */ url(images/icons/comment.svg);
-}
-.oo-ui-icon-expand {
- background-image: /* @embed */ url(images/icons/expand.svg);
-}
-.oo-ui-icon-help {
- background-image: /* @embed */ url(images/icons/help.svg);
-}
-.oo-ui-icon-info {
- background-image: /* @embed */ url(images/icons/info.svg);
-}
-.oo-ui-icon-link {
- background-image: /* @embed */ url(images/icons/link.svg);
-}
-.oo-ui-icon-menu {
- background-image: /* @embed */ url(images/icons/menu.svg);
-}
-.oo-ui-icon-next {
- background-image: /* @embed */ url(images/icons/move-rtl.svg);
-}
-.oo-ui-icon-picture {
- background-image: /* @embed */ url(images/icons/picture.svg);
-}
-.oo-ui-icon-previous {
- background-image: /* @embed */ url(images/icons/move-ltr.svg);
-}
-.oo-ui-icon-redo {
- background-image: /* @embed */ url(images/icons/arched-arrow-rtl.svg);
-}
-.oo-ui-icon-remove {
- background-image: /* @embed */ url(images/icons/remove.svg);
-}
-.oo-ui-icon-search {
- background-image: /* @embed */ url(images/icons/search.svg);
-}
-.oo-ui-icon-settings {
- background-image: /* @embed */ url(images/icons/settings.svg);
-}
-.oo-ui-icon-tag {
- background-image: /* @embed */ url(images/icons/tag.svg);
-}
-.oo-ui-icon-undo {
- background-image: /* @embed */ url(images/icons/arched-arrow-ltr.svg);
-}
-.oo-ui-icon-window {
- background-image: /* @embed */ url(images/icons/window.svg);
-}
-.oo-ui-indicator-alert {
- background-image: /* @embed */ url(images/indicators/alert.svg);
-}
-.oo-ui-indicator-down {
- background-image: /* @embed */ url(images/indicators/arrow-down.svg);
-}
-.oo-ui-indicator-next {
- background-image: /* @embed */ url(images/indicators/arrow-rtl.svg);
-}
-.oo-ui-indicator-previous {
- background-image: /* @embed */ url(images/indicators/arrow-ltr.svg);
-}
-.oo-ui-indicator-required {
- background-image: /* @embed */ url(images/indicators/required.svg);
-}
-.oo-ui-indicator-up {
- background-image: /* @embed */ url(images/indicators/arrow-up.svg);
-}
-.oo-ui-texture-pending {
- background-image: /* @embed */ url(images/textures/pending.gif);
-}
-.oo-ui-texture-transparency {
- background-image: /* @embed */ url(images/textures/transparency.svg);
-}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.png
new file mode 100644
index 00000000..c65a5c1e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.svg
new file mode 100644
index 00000000..0d37afab
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #00AF89 }</style>
+ <g id="add">
+ <path id="plus" d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.png
new file mode 100644
index 00000000..d6144e3d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.svg
new file mode 100644
index 00000000..93a1c6ef
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="add">
+ <path id="plus" d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/add.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add.png
new file mode 100644
index 00000000..730d1029
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/add-item.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add.svg
index c42731a1..29e5dba8 100644
--- a/resources/lib/oojs-ui/images/icons/add-item.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="add-item" opacity=".75">
+ <g id="add">
<path id="plus" d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.png
new file mode 100644
index 00000000..733c3f97
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.svg
new file mode 100644
index 00000000..fe3dc5b2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M20 14.5v-2.9l-1.8-.3c-.1-.4-.3-.8-.6-1.4l1.1-1.5-2.1-2.1-1.5 1.1c-.5-.3-1-.5-1.4-.6l-.2-1.8h-2.9l-.3 1.8c-.5.1-.9.3-1.4.6l-1.5-1.1-2.1 2.1 1 1.5c-.3.5-.4.9-.6 1.4l-1.7.2v2.9l1.8.3c.1.5.3.9.6 1.4l-1 1.5 2.1 2.1 1.5-1c.4.2.9.4 1.4.6l.3 1.8h3l.3-1.8c.5-.1.9-.3 1.4-.6l1.5 1.1 2.1-2.1-1.1-1.5c.3-.5.5-1 .6-1.4l1.5-.3zm-8 1.5c-1.7 0-3-1.3-3-3s1.3-3 3-3 3 1.3 3 3-1.3 3-3 3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.png
new file mode 100644
index 00000000..7dab898d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.svg
new file mode 100644
index 00000000..b4629bf9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M20 14.5v-2.9l-1.8-.3c-.1-.4-.3-.8-.6-1.4l1.1-1.5-2.1-2.1-1.5 1.1c-.5-.3-1-.5-1.4-.6l-.2-1.8h-2.9l-.3 1.8c-.5.1-.9.3-1.4.6l-1.5-1.1-2.1 2.1 1 1.5c-.3.5-.4.9-.6 1.4l-1.7.2v2.9l1.8.3c.1.5.3.9.6 1.4l-1 1.5 2.1 2.1 1.5-1c.4.2.9.4 1.4.6l.3 1.8h3l.3-1.8c.5-.1.9-.3 1.4-.6l1.5 1.1 2.1-2.1-1.1-1.5c.3-.5.5-1 .6-1.4l1.5-.3zm-8 1.5c-1.7 0-3-1.3-3-3s1.3-3 3-3 3 1.3 3 3-1.3 3-3 3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.png
new file mode 100644
index 00000000..5440113f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.svg
new file mode 100644
index 00000000..715a3f55
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="alert">
+ <path id="point" d="M11 16h2v2h-2z"/>
+ <path id="stroke" d="M13.516 10h-3l.484 5h2z"/>
+ <path id="triangle" d="M12.017 5.974l7.519 13.026h-15.04l7.521-13.026m0-2.474c-.544 0-1.088.357-1.5 1.071l-7.985 13.831c-.825 1.429-.15 2.598 1.5 2.598h15.968c1.65 0 2.325-1.169 1.5-2.599l-7.983-13.829c-.413-.715-.956-1.072-1.5-1.072z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.png
new file mode 100644
index 00000000..fcf98c5d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.svg
new file mode 100644
index 00000000..6928cab4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FF5D00 }</style>
+ <g id="alert">
+ <path id="point" d="M11 16h2v2h-2z"/>
+ <path id="stroke" d="M13.516 10h-3l.484 5h2z"/>
+ <path id="triangle" d="M12.017 5.974l7.519 13.026h-15.04l7.521-13.026m0-2.474c-.544 0-1.088.357-1.5 1.071l-7.985 13.831c-.825 1.429-.15 2.598 1.5 2.598h15.968c1.65 0 2.325-1.169 1.5-2.599l-7.983-13.829c-.413-.715-.956-1.072-1.5-1.072z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.png
new file mode 100644
index 00000000..e98a14a9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/alert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.svg
index 819e062a..f0c65224 100644
--- a/resources/lib/oojs-ui/images/icons/alert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="alert" opacity=".75">
+ <g id="alert">
<path id="point" d="M11 16h2v2h-2z"/>
<path id="stroke" d="M13.516 10h-3l.484 5h2z"/>
<path id="triangle" d="M12.017 5.974l7.519 13.026h-15.04l7.521-13.026m0-2.474c-.544 0-1.088.357-1.5 1.071l-7.985 13.831c-.825 1.429-.15 2.598 1.5 2.598h15.968c1.65 0 2.325-1.169 1.5-2.599l-7.983-13.829c-.413-.715-.956-1.072-1.5-1.072z"/>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.png
new file mode 100644
index 00000000..92d231e2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.svg
new file mode 100644
index 00000000..887c2f66
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="align-center">
+ <path d="M9 9h6c.554 0 1 .446 1 1v5c0 .554-.446 1-1 1h-6c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zM3.5 18h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM3.5 6h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left.png
new file mode 100644
index 00000000..2880478c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left.svg
new file mode 100644
index 00000000..ce9761e2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="align-float-left">
+ <path d="M4 9h6c.554 0 1 .446 1 1v5c0 .554-.446 1-1 1h-6c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zM13.5 9h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM13.5 12h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM13.5 15h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM3.5 6h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zM3.5 18h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right.png
new file mode 100644
index 00000000..e9c2f0ea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right.svg
new file mode 100644
index 00000000..557692ae
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="align-float-right">
+ <path d="M20 9h-6c-.554 0-1 .446-1 1v5c0 .554.446 1 1 1h6c.554 0 1-.446 1-1v-5c0-.554-.446-1-1-1zM10.5 9h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM10.5 12h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM10.5 15h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM20.5 6h-17c-.277 0-.5.223-.5.5s.223.5.5.5h17c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zM20.5 18h-17c-.277 0-.5.223-.5.5s.223.5.5.5h17c.277 0 .5-.223.5-.5s-.223-.5-.5-.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr-invert.png
new file mode 100644
index 00000000..37b57fe5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr-invert.svg
new file mode 100644
index 00000000..9aca4158
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve"><style>* { fill: #FFFFFF }</style>
+<path d="M-472.8,494.7l6.3,5.7l-6.3,5.7v-3.8h-1.3c-3.2,0-6.3,1.3-7.6,3.8c0-4.7,2.8-7.6,7.9-7.6h0.9V494.7z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr.png
new file mode 100644
index 00000000..7d2113f2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr.svg
new file mode 100644
index 00000000..049f21e2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
+<path d="M-472.8,494.7l6.3,5.7l-6.3,5.7v-3.8h-1.3c-3.2,0-6.3,1.3-7.6,3.8c0-4.7,2.8-7.6,7.9-7.6h0.9V494.7z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl-invert.png
new file mode 100644
index 00000000..a50b3066
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl-invert.svg
new file mode 100644
index 00000000..11fffcb2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve"><style>* { fill: #FFFFFF }</style>
+<path d="M-476.3,494.7l-6.3,5.7l6.3,5.7v-3.8h1.3c3.2,0,6.3,1.3,7.6,3.8c0-4.7-2.8-7.6-7.9-7.6h-0.9V494.7z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl.png
new file mode 100644
index 00000000..ed69a011
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl.svg
new file mode 100644
index 00000000..20875f34
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
+<path d="M-476.3,494.7l-6.3,5.7l6.3,5.7v-3.8h1.3c3.2,0,6.3,1.3,7.6,3.8c0-4.7-2.8-7.6-7.9-7.6h-0.9V494.7z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr.png
new file mode 100644
index 00000000..8bef0a51
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr.svg
new file mode 100644
index 00000000..b07621e8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g4">
+ <path d="M16 12h-10c-1.7 0-3 1.3-3 3h13v3l5-4.5-5-4.5v3z" id="path6"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl.png
new file mode 100644
index 00000000..26e3e69f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl.svg
new file mode 100644
index 00000000..a0189283
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M8 12h10c1.7 0 3 1.3 3 3h-13v3l-5-4.5 5-4.5v3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr.png
new file mode 100644
index 00000000..99dd6382
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr.svg
new file mode 100644
index 00000000..b719946d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M12 10h4v-5h-4v5zm-5 2h9v-1h-9v1zm0 2h9v-1h-9v1zm0 2h9v-1h-9v1zm4-9h-4v1h4v-1zm0 2h-4v1h4v-1zm0-4h-4v1h4v-1zm-6-2h13v16h-10c-1.7 0-3-1.3-3-3v-13z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl.png
new file mode 100644
index 00000000..e5e47aa6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl.svg
new file mode 100644
index 00000000..f14dfbda
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g16">
+ <path d="M11 10h-4v-5h4v5zm5 2h-9v-1h9v1zm0 2h-9v-1h9v1zm0 2h-9v-1h9v1zm-4-9h4v1h-4v-1zm0 2h4v1h-4v-1zm0-4h4v1h-4v-1zm6-2h-13v16h10c1.7 0 3-1.3 3-3v-13z" id="path18"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.png
new file mode 100644
index 00000000..a7c76b80
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.svg
new file mode 100644
index 00000000..77119710
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <g>
+ <path d="M21 11l-6 7-4-4-1 1 5 5 7-8z"/>
+ </g>
+ <path d="M17 14v-11h-13v13c0 1.7 1.3 3 3 3h5l-3-3h-3v-1h2.6l1-1h-3.6v-1h9v1h-2l1 1h2l1-1zm-11-9h4v1h-4v-1zm0 2h4v1h-4v-1zm0 2h4v1h-4v-1zm9 3h-9v-1h9v1zm-4-2v-5h4v5h-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.png
new file mode 100644
index 00000000..314b8eb4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.svg
new file mode 100644
index 00000000..771b3ffb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g28">
+ <g id="g30">
+ <path d="M5 11l6 7 4-4 1 1-5 5-7-8z" id="path32"/>
+ </g>
+ <path d="M9 14v-11h13v13c0 1.7-1.3 3-3 3h-5l3-3h3v-1h-2.6l-1-1h3.6v-1h-9v1h2l-1 1h-2l-1-1zm11-9h-4v1h4v-1zm0 2h-4v1h4v-1zm0 2h-4v1h4v-1zm-9 3h9v-1h-9v1zm4-2v-5h-4v5h4z" id="path34"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr.png
new file mode 100644
index 00000000..93f8624d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr.svg
new file mode 100644
index 00000000..e54c0c4a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M19.1 18.5c.6-.7.9-1.5.9-2.5 0-2.2-1.8-4-4-4s-4 1.8-4 4 1.8 4 4 4c.7 0 1.3-.1 1.8-.4l2.7 2.7 1.1-1.1-2.5-2.7zm-3.1-.3c-1.2 0-2.2-1-2.2-2.3 0-1.2 1-2.2 2.2-2.2 1.2 0 2.3 1 2.3 2.2-.1 1.3-1.1 2.3-2.3 2.3zm-4.2-5.2c.3-.4.6-.7 1-1h-5.8v-1h9s1.2 0 2 .6v-8.6h-13v13c0 1.7 1.3 3 3 3h3.8c-.6-.8-1-1.9-1-3h-3.8v-1h3.9l.3-1h-4.2v-1h4.8zm.2-8h4v5h-4v-5zm-5 0h4v1h-4v-1zm0 2h4v1h-4v-1zm0 2h4v1h-4v-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl.png
new file mode 100644
index 00000000..7cf4ac86
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl.svg
new file mode 100644
index 00000000..31134f1c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g44">
+ <path d="M7.5 18.5c-.6-.7-.9-1.5-.9-2.5 0-2.2 1.8-4 4-4s4 1.8 4 4-1.8 4-4 4c-.7 0-1.3-.1-1.8-.4l-2.7 2.7-1.1-1.1 2.5-2.7zm3.1-.3c1.2 0 2.2-1 2.2-2.3 0-1.2-1-2.2-2.2-2.2-1.2 0-2.3 1-2.3 2.2.1 1.3 1.1 2.3 2.3 2.3zm4.2-5.2c-.3-.4-.6-.7-1-1h5.8v-1h-9s-1.2 0-2 .6v-8.6h13v13c0 1.7-1.3 3-3 3h-3.8c.6-.8 1-1.9 1-3h3.8v-1h-3.9l-.3-1h4.2v-1h-4.8zm-.2-8h-4v5h4v-5zm5 0h-4v1h4v-1zm0 2h-4v1h4v-1zm0 2h-4v1h4v-1z" id="path46"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.png
new file mode 100644
index 00000000..948443fd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.svg
new file mode 100644
index 00000000..df08800f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M17.5 14v-5c0-3-2.3-5-5.5-5s-5.5 2-5.5 5v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zm-5.5 6h-3c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.png
new file mode 100644
index 00000000..4450e690
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.svg
new file mode 100644
index 00000000..f419e79f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M17.8 14.7l1.7-4.7c1-2.8-.5-5.5-3.5-6.6s-5.9 0-6.9 2.8l-1.7 4.7c-.7 1.9-1 2.8-2.9 2.1l-.3 1 14.1 5.1.3-.9c-1.9-.7-1.5-1.6-.8-3.5zm-5.8 5.1l-2.8-1c-.3.9.8 2.4 2.1 2.9s3.2.1 3.5-.9l-2.8-1z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.png
new file mode 100644
index 00000000..b236b999
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.svg
new file mode 100644
index 00000000..e4c3a3fa
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M6.209 14.7l-1.7-4.7c-1-2.8.5-5.5 3.5-6.6 3-1.1 5.9 0 6.9 2.8l1.7 4.7c.7 1.9 1 2.8 2.9 2.1l.3 1-14.1 5.1-.3-.9c1.9-.7 1.5-1.6.8-3.5zm5.8 5.1l2.8-1c.3.9-.8 2.4-2.1 2.9s-3.2.1-3.5-.9l2.8-1z" id="path56"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta.png
new file mode 100644
index 00000000..ef3e20ad
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta.svg
new file mode 100644
index 00000000..51a5c782
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12 4c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm4 12l-3-2-1 4-1-4-3 2 2-3-4-1 4-1-2-3 3 2 1-4 1 4 3-2-2 3 4 1-4 1 2 3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.png
new file mode 100644
index 00000000..f1e48aca
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.svg
new file mode 100644
index 00000000..a693b59b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M15.3 14.7c.8-3.8-.6-10.7-3.3-10.7-2.7 0-4.2 6.7-3.4 10.5l-1.6 3.5h2.7l.3 1h4c.2-.3.1-.5.3-1h2.7l-1.7-3.3zm-3.3-4.7c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm2 10c0 1.1-2 2-2 2s-2-.9-2-2"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.png
new file mode 100644
index 00000000..b1c13a23
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.svg
new file mode 100644
index 00000000..94ec6704
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12.666 6h-1.372l-4.48 12h1.705l1.494-4h3.999l1.508 4h1.666l-4.52-12zm-2.28 7l1.617-4.333 1.634 4.333h-3.251z" id="a"/>
+ <g id="up">
+ <path id="arrow" d="M15.5 9h7l-3.5-6z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.png
new file mode 100644
index 00000000..052ae37f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.svg
new file mode 100644
index 00000000..b2a6c139
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12.666 6h-1.372l-4.48 12H8.52l1.493-4h4l1.507 4h1.666l-4.52-12zm-2.28 7l1.617-4.333L13.637 13h-3.25z" id="a"/>
+ <g id="up">
+ <path id="arrow" d="M1.5 9h7L5 3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.png
new file mode 100644
index 00000000..3e919971
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.svg
new file mode 100644
index 00000000..c850e65b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #D11D13 }</style>
+ <path d="M12 4c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm5 9h-10v-2h10v2z" id="path4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.png
new file mode 100644
index 00000000..9529e5b0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.svg
new file mode 100644
index 00000000..289ef4fd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M12 4c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm5 9h-10v-2h10v2z" id="path4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/block.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block.png
new file mode 100644
index 00000000..181daceb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/block.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block.svg
new file mode 100644
index 00000000..0ddd1d47
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12 4c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm5 9h-10v-2h10v2z" id="path4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr-invert.png
new file mode 100644
index 00000000..aeee727b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr-invert.svg
new file mode 100644
index 00000000..94089371
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g66">
+ <path d="M17 11v2h-2l3.6 3.6c.9-1.3 1.4-2.9 1.4-4.6 0-4.4-3.6-8-8-8-1.7 0-3.3.5-4.6 1.4l5.6 5.6h4zm-13-7l-1 1 2.4 2.4c-.9 1.3-1.4 2.9-1.4 4.6 0 4.4 3.6 8 8 8 1.7 0 3.3-.5 4.6-1.4l2.4 2.4 1-1-16-16zm3 9v-2h2l2 2h-4z" id="path68"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr.png
new file mode 100644
index 00000000..76e0db4b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr.svg
new file mode 100644
index 00000000..3d9cfd7d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g66">
+ <path d="M17 11v2h-2l3.6 3.6c.9-1.3 1.4-2.9 1.4-4.6 0-4.4-3.6-8-8-8-1.7 0-3.3.5-4.6 1.4l5.6 5.6h4zm-13-7l-1 1 2.4 2.4c-.9 1.3-1.4 2.9-1.4 4.6 0 4.4 3.6 8 8 8 1.7 0 3.3-.5 4.6-1.4l2.4 2.4 1-1-16-16zm3 9v-2h2l2 2h-4z" id="path68"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl-invert.png
new file mode 100644
index 00000000..46b680c4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl-invert.svg
new file mode 100644
index 00000000..ba48235d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g66">
+ <path d="M7 11v2h2l-3.6 3.6c-.9-1.3-1.4-2.9-1.4-4.6 0-4.4 3.6-8 8-8 1.7 0 3.3.5 4.6 1.4l-5.6 5.6h-4zm13-7l1 1-2.4 2.4c.9 1.3 1.4 2.9 1.4 4.6 0 4.4-3.6 8-8 8-1.7 0-3.3-.5-4.6-1.4l-2.4 2.4-1-1 16-16zm-3 9v-2h-2l-2 2h4z" id="path68"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl.png
new file mode 100644
index 00000000..e31809e5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl.svg
new file mode 100644
index 00000000..8f807596
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g66">
+ <path d="M7 11v2h2l-3.6 3.6c-.9-1.3-1.4-2.9-1.4-4.6 0-4.4 3.6-8 8-8 1.7 0 3.3.5 4.6 1.4l-5.6 5.6h-4zm13-7l1 1-2.4 2.4c.9 1.3 1.4 2.9 1.4 4.6 0 4.4-3.6 8-8 8-1.7 0-3.3-.5-4.6-1.4l-2.4 2.4-1-1 16-16zm-3 9v-2h-2l-2 2h4z" id="path68"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.png
new file mode 100644
index 00000000..86611e35
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.svg
new file mode 100644
index 00000000..4b828779
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-a">
+ <path d="M16 18h3l-5-12h-3l-5 12h3l1.25-3h4.5l1.25 3zm-4.917-5l1.417-3.4 1.417 3.4h-2.834z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain.png
new file mode 100644
index 00000000..871da471
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain.svg
new file mode 100644
index 00000000..f96cebce
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-arab-ain">
+ <path id="arab-ain" d="M9.337 13.616c0 1.349 1.386 2.101 4.159 2.258l2.187-.029.318.044c-.03.127-.251.345-.665.652l-.089.066c-1.236.929-2.423 1.393-3.56 1.393-1.143 0-2.046-.33-2.711-.99-.65-.66-.975-1.559-.975-2.698.005-1.354.566-2.573 1.684-3.658v-.044l-.606-.55c-.148-.181-.222-.391-.222-.63 0-.489.239-1.109.717-1.862.65-1.046 1.303-1.566 1.958-1.561.886.005 1.618.42 2.194 1.246.325.479-.03.552-1.064.22-.842-.327-1.527-.051-2.054.828l.015.073 1.123.865.052.007c1.404-.498 2.418-.74 3.043-.726-.059.117-.14.362-.244.733-.103.357-.204.684-.303.982l-.126.374-.384.051c-1.743.239-2.992.716-3.745 1.429-.463.464-.697.973-.702 1.525"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.png
new file mode 100644
index 00000000..ad6f342f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.svg
new file mode 100644
index 00000000..f04c6aad
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-arab-dad">
+ <path id="arab-dad" d="M16.411 8.232l-1.676-.665.694-1.567 1.688.64-.707 1.592m.775 3.078c-.509-.286-1-.427-1.476-.423-.471 0-.982.205-1.532.616l-.506.379.006.025c1.084.066 1.934.099 2.551.099h.313c.567-.021.992-.064 1.276-.131-.067-.17-.275-.359-.625-.566h-.006m-6.803 3.296c-.017-.904-.329-1.87-.938-2.898l1.294-1.729.119.149c.267.336.504.924.713 1.766l.063.05c.496-.008.942-.17 1.338-.485v-.006l1.732-1.53c.679-.601 1.282-.902 1.807-.902.383.004.848.195 1.394.572.55.377.884.696 1 .958.063.149.094.386.094.709 0 .696-.11 1.229-.331 1.598-.192.311-.473.555-.844.734-.438.207-1.549.311-3.333.311-.8 0-1.795-.021-2.983-.062l-.144.429c-.254.672-.463 1.113-.625 1.324-.725.937-1.786 1.405-3.183 1.405-1.705-.008-2.557-.922-2.557-2.742.004-.941.279-1.814.825-2.618.15-.216.298-.367.444-.454.225-.133.288-.091.188.124-.396.862-.596 1.548-.6 2.058.008 1.177.752 1.768 2.232 1.772 1.038-.004 1.803-.182 2.295-.535"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to.png
new file mode 100644
index 00000000..c4af66e7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to.svg
new file mode 100644
index 00000000..4dbec6d9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-armn-to">
+ <path id="armn-to" d="M13.86 16.257c.124 0 .254-.026.39-.078.135-.058.257-.15.367-.274.114-.13.205-.302.273-.516.073-.213.11-.48.11-.797V13h-1.14c-.14 0-.284.026-.43.078-.14.047-.27.133-.383.258-.11.125-.2.294-.274.508-.067.213-.1.487-.1.82 0 .34.035.47.108.695.08.218.175.395.29.53.12.136.247.232.383.29.14.05.276.077.406.077m-2.97-7.84c-.37.082-.695.247-.976.45-.28.198-.505.47-.672.813-.16.343-.242.78-.242 1.312V18H6v-7.188c0-.776.15-1.455.453-2.04.302-.587.714-1.077 1.234-1.467.52-.39 1.13-.685 1.83-.883.697-.198 1.44-.297 2.225-.297.526 0 1.04.044 1.54.133.504.088.98.22 1.43.398.447.172.858.388 1.233.65.375.26.698.564.97.913.275.348.49.738.64 1.17.15.433.226 1.094.226 1.61h1.353v2.04H17.78v1.6c0 .58-.103 1.092-.31 1.54-.21.442-.49.815-.845 1.117-.35.302-.834.53-1.297.687-.464.15-.953.226-1.47.226-.51 0-.996-.078-1.46-.234-.464-.156-.87-.39-1.22-.703-.348-.313-.626-.703-.835-1.172-.203-.473-.304-1.028-.304-1.663s.105-1.182.32-1.64c.213-.46.497-.685.85-.977.355-.297.76-.513 1.22-.648.458-.14.935-.21 1.43-.21h1.132c-.01-.49-.04-1.043-.242-1.36-.198-.323-.453-.58-.766-.766-.312-.193-.598-.332-.984-.426-.374-.09-.577-.094-1.1-.094-.52 0-.64.02-1.01.102z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.png
new file mode 100644
index 00000000..b1c6955b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.svg
new file mode 100644
index 00000000..4f648203
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-b">
+ <path id="b" d="M7 18h6c2 0 4-1 4-3 0-1.064.011-1.975-1.989-3 2-.975 1.989-1.935 1.989-3 0-2-2-3-4-3h-6v12zm7-8c0 1.001 0 1-2 1h-2v-3h2c2 0 2 0 2 1v1zm-2 6h-2v-3h2c2 0 2 0 2 1v1s0 1-2 1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be.png
new file mode 100644
index 00000000..dc310511
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be.svg
new file mode 100644
index 00000000..279466d4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-cyrl-be">
+ <path id="cyrl-be" d="M7 6h9v2h-6v3h2.649c.893 0 1.633.109 2.22.327.588.218 1.088.622 1.502 1.211.419.589.629 1.187.629 1.978 0 .813-.21 1.398-.629 1.977-.419.578-.898.974-1.437 1.187-.533.213-1.295.319-2.286.319h-5.649m4.767-2c.751 0 1.279-.049 1.584-.12.305-.076.569-.246.792-.508.229-.262.343-.473.343-.855 0-.557-.199-.868-.596-1.119-.392-.256-1.064-.398-2.016-.398h-1.873v3"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te.png
new file mode 100644
index 00000000..6058d8f1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te.svg
new file mode 100644
index 00000000..fdeeb6c5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-cyrl-te">
+ <path id="te" d="M11 18v-10h-4v-2h11v2h-4v10"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe.png
new file mode 100644
index 00000000..3084fef2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe.svg
new file mode 100644
index 00000000..5996c813
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-cyrl-zhe">
+ <path id="cyrl-zhe" d="M13 6v5.154c.328-.033.537-.181.705-.447.168-.266.401-.873.698-1.821.39-1.241.789-2.033 1.197-2.374.403-.336 1.075-.504 2.014-.504l.386-.008v1.78l-.386-.008c-.399 0-.691.062-.878.187-.186.119-.337.304-.452.553-.115.249-.286.762-.512 1.537-.12.412-.25.756-.392 1.033-.137.276-.383.537-.738.78.439.157.8.466 1.084.927.288.455.603 1.103.944 1.943l1.33 3.268h-2.314l-1.17-3.081-.113-.252-.239-.561c-.248-.569-.452-.932-.612-1.089-.16-.157-.317-.236-.552-.236v5.22h-2v-5.22c-.226 0-.382.076-.546.228-.164.152-.368.518-.612 1.098l-.246.561-.113.252-1.17 3.081h-2.314l1.33-3.268c.328-.808.636-1.447.924-1.919.293-.477.663-.794 1.11-.951-.355-.244-.603-.501-.745-.772-.137-.276-.268-.623-.392-1.041-.222-.759-.39-1.266-.505-1.52-.111-.255-.261-.444-.452-.569-.186-.125-.492-.187-.917-.187l-.352.008v-1.78l.386.008c.953 0 1.631.171 2.034.512.399.347.791 1.136 1.177 2.366.301.954.534 1.564.698 1.829.168.26.377.406.705.439v-5.154"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.png
new file mode 100644
index 00000000..e650eb60
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.svg
new file mode 100644
index 00000000..357d2e5d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-f">
+ <path id="f" d="M16 8v-2h-8v12h3v-5h4v-2h-4v-3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.png
new file mode 100644
index 00000000..e30e1fea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.svg
new file mode 100644
index 00000000..e032542e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-g">
+ <path id="g" d="M12 14v-2h5v4.203c-.497.475-1.22.894-2.166 1.259-.941.359-1.896.538-2.864.538-1.23 0-2.303-.253-3.217-.76-.915-.512-1.602-1.24-2.062-2.185-.46-.95-.69-1.982-.69-3.095 0-1.208.257-2.282.77-3.222.513-.939 1.265-1.66 2.255-2.161.754-.385 1.693-.578 2.816-.578 1.46 0 2.6.303 3.418.91.824.602 1.353 1.435 1.589 2.501l-2.359.435c-.166-.57-.479-1.018-.939-1.346-.455-.332-1.024-.499-1.709-.499-1.038 0-1.864.325-2.479.974-.61.649-.915 1.612-.915 2.889 0 1.377.31 2.412.931 3.103.62.686 1.433 1.029 2.439 1.029.497 0 .995-.095 1.492-.285.503-.195 1.332-.571 1.691-.845v-.867"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man.png
new file mode 100644
index 00000000..814eff89
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man.svg
new file mode 100644
index 00000000..b211bf7a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-geor-man">
+ <path id="geor-man" d="M13.832 14.061c0-1.715-.394-2.573-1.182-2.573-.868 0-1.302.779-1.302 2.338-.01 1.624.421 2.436 1.295 2.436.793 0 1.189-.734 1.189-2.201m2.168 0c0 2.626-1.116 3.939-3.349 3.939-2.434 0-3.651-1.386-3.651-4.159 0-2.738 1.217-4.106 3.651-4.106.841 0 1.182.63 1.182.63v-1.579c0-.789-.449-1.184-1.347-1.184-.572 0-.858.374-.858 1.123h-2.341c.005-1.817 1.064-2.725 3.176-2.725 2.368 0 3.548.946 3.538 2.839"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.png
new file mode 100644
index 00000000..ff021ce3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.svg
new file mode 100644
index 00000000..16797938
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-l">
+ <path id="l" d="M8 18v-12h3v10h5v2"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.png
new file mode 100644
index 00000000..7ae9321b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.svg
new file mode 100644
index 00000000..73ad019a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-n">
+ <path id="n" d="M7 18v-12h3l4 8v-8h3v12h-3l-4-8v8h-3"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.png
new file mode 100644
index 00000000..39c2be04
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.svg
new file mode 100644
index 00000000..146943a5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="bold-v">
+ <path id="v" d="M10.5 18l-4.5-12h3l3 8 3-8h3l-4.5 12"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.png
new file mode 100644
index 00000000..636d3bde
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.svg
new file mode 100644
index 00000000..7a058ed3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M15 7c-1.7 0-3 1.3-3 3 0-1.7-1.3-3-3-3h-6v13h6c1.7 0 3 1 3 2 0-1 1.3-2 3-2h6v-13h-6zm5 12h-5c-1.7 0-2 .4-2 .4v-8.9c0-1.4 1.1-2.5 2.5-2.5h4.5v11z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.png
new file mode 100644
index 00000000..87f91891
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.svg
new file mode 100644
index 00000000..6ae47ec5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M9 7c1.7 0 3 1.3 3 3 0-1.7 1.3-3 3-3h6v13h-6c-1.7 0-3 1-3 2 0-1-1.3-2-3-2h-6v-13h6zm-5 12h5c1.7 0 2 .4 2 .4v-8.9c0-1.4-1.1-2.5-2.5-2.5h-4.5v11z" id="path78"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.png
new file mode 100644
index 00000000..371dfc6c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.svg
new file mode 100644
index 00000000..d803d6be
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M15 5h-7c-1.1 0-2 .9-2 2v3h3v11l4-3 4 3v-14c0-1.1-.9-2-2-2zm-6 4h-2v-2c0-.6.4-1 1-1h1v3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.png
new file mode 100644
index 00000000..4a50c17d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.svg
new file mode 100644
index 00000000..744d0f4e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M8 5h7c1.1 0 2 .9 2 2v3h-3v11l-4-3-4 3v-14c0-1.1.9-2 2-2zm6 4h2v-2c0-.6-.4-1-1-1h-1v3z" id="path88"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.png
new file mode 100644
index 00000000..80f1a476
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.svg
new file mode 100644
index 00000000..7bd04250
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M3 6v11c0 1.7 1.3 3 3 3h15v-14h-18zm2.5 1c.8 0 1.5.7 1.5 1.5s-.7 1.5-1.5 1.5-1.5-.7-1.5-1.5.7-1.5 1.5-1.5zm14.5 12h-14c-1.1 0-2-.9-2-2v-6h16v8z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.png
new file mode 100644
index 00000000..ea215df9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.svg
new file mode 100644
index 00000000..84b18dae
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M21 6v11c0 1.7-1.3 3-3 3h-15v-14h18zm-2.5 1c-.8 0-1.5.7-1.5 1.5s.7 1.5 1.5 1.5 1.5-.7 1.5-1.5-.7-1.5-1.5-1.5zm-14.5 12h14c1.1 0 2-.9 2-2v-6h-16v8z" id="path98"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.png
new file mode 100644
index 00000000..5668e127
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.svg
new file mode 100644
index 00000000..8a9d3d4d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="cancel">
+ <path id="circle-with-strike" d="M11.999 5.022c-3.853 0-6.977 3.124-6.977 6.978 0 3.853 3.124 6.978 6.977 6.978 3.854 0 6.979-3.125 6.979-6.978 0-3.854-3.125-6.978-6.979-6.978zm-5.113 6.978c0-1.092.572-3.25.93-2.929l7.113 7.113c.488.525-1.837.931-2.93.931-2.825-.001-5.113-2.291-5.113-5.115zm9.298 2.929l-7.114-7.113c-.445-.483 1.837-.931 2.929-.931 2.827 0 5.115 2.289 5.115 5.114 0 1.093-.364 3.543-.93 2.93z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.png
new file mode 100644
index 00000000..51a33ff8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/clear.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.svg
index 8409c679..bfc1b44b 100644
--- a/resources/lib/oojs-ui/images/icons/clear.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="clear" opacity=".75">
+ <g id="cancel">
<path id="circle-with-strike" d="M11.999 5.022c-3.853 0-6.977 3.124-6.977 6.978 0 3.853 3.124 6.978 6.977 6.978 3.854 0 6.979-3.125 6.979-6.978 0-3.854-3.125-6.978-6.979-6.978zm-5.113 6.978c0-1.092.572-3.25.93-2.929l7.113 7.113c.488.525-1.837.931-2.93.931-2.825-.001-5.113-2.291-5.113-5.115zm9.298 2.929l-7.114-7.113c-.445-.483 1.837-.931 2.929-.931 2.827 0 5.115 2.289 5.115 5.114 0 1.093-.364 3.543-.93 2.93z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.png
new file mode 100644
index 00000000..a42aaa5d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.svg
new file mode 100644
index 00000000..f31ec095
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M7 13.1l8.9 8.9c.8-.8.8-2 0-2.8l-6.1-6.1 6-6.1c.8-.8.8-2 0-2.8l-8.8 8.9z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.png
new file mode 100644
index 00000000..9064f617
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.svg
new file mode 100644
index 00000000..02b4e387
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M16.5 13.1l-8.9 8.9c-.8-.8-.8-2 0-2.8l6.1-6.1-6-6.1c-.8-.8-.8-2 0-2.8l8.8 8.9z" id="path108"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.png
new file mode 100644
index 00000000..bc453ea5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.svg
new file mode 100644
index 00000000..a04ca572
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12 16l8.9-8.9c-.8-.8-2-.8-2.8 0l-6.1 6.1-6.1-6c-.8-.8-2-.8-2.8 0l8.9 8.8z" id="path4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.png
new file mode 100644
index 00000000..55910950
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.svg
new file mode 100644
index 00000000..d0e0c283
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12 6.5l8.9 8.9c-.8.8-2 .8-2.8 0l-6.1-6.1-6.1 6c-.8.8-2 .8-2.8 0l8.9-8.8z" id="path4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.png
new file mode 100644
index 00000000..e30bf2dd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.svg
new file mode 100644
index 00000000..824790c5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="regular-expression">
+ <path id="upper-case" d="M 7.53125,7 4,17 l 2.0625,0 0.71875,-2.40625 3.625,0 L 11.125,17 13.1875,17 9.65625,7 7.53125,7 z M 8.59375,8.53125 9.9375,13 7.25,13 8.59375,8.53125 z" />
+ <path id="lower-case" d="m 18.548697,17 -0.183254,-1.035072 -0.05451,0 c -0.349771,0.440361 -0.710892,0.746796 -1.083366,0.919307 -0.367941,0.167972 -0.849436,0.251959 -1.444489,0.251959 -0.564328,0 -0.954665,-0.20883 -1.377109,-0.626492 -0.417903,-0.417659 -0.626854,-1.012371 -0.626853,-1.784137 -1e-6,-0.80808 0.281628,-1.402791 0.844889,-1.784137 0.567801,-0.385878 1.193222,-0.607062 2.208372,-0.640111 l 1.321843,-0.04086 0,-0.333674 c 0,-0.771759 -0.395195,-1.15764 -1.185571,-1.157647 -0.608688,7e-6 -1.324118,0.183867 -2.146293,0.551584 L 14.134181,9.9184512 c 0.876685,-0.4585114 1.848761,-0.6877705 2.916233,-0.6877783 1.022038,7.8e-6 1.586855,0.2224573 2.131951,0.6673492 C 19.727448,10.342928 20,11.019356 20,11.927309 l 0,5.073215 -1.451303,0 m -0.394476,-3.527417 -0.804008,0.02724 c -0.604145,0.01816 -1.053844,0.127119 -1.349098,0.326866 -0.29526,0.199753 -0.442889,0.503919 -0.442886,0.912498 -3e-6,0.585634 0.336136,0.878451 1.008417,0.878449 0.481492,2e-6 0.865326,-0.138462 1.151503,-0.415391 0.29071,-0.276925 0.436067,-0.644648 0.436072,-1.103169 l 0,-0.626491" />
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-constructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-constructive.png
new file mode 100644
index 00000000..875fa68c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-constructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-constructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-constructive.svg
new file mode 100644
index 00000000..e55233f3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-constructive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #00AF89 }</style>
+ <g id="check">
+ <path d="M17 7.5L9.5 15 6 11.5 4.5 13l5 5L20 7.5c-.706-.706-2.294-.706-3 0z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-invert.png
new file mode 100644
index 00000000..83ba2b0f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-invert.svg
new file mode 100644
index 00000000..77d90dca
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="check">
+ <path d="M17 7.5L9.5 15 6 11.5 4.5 13l5 5L20 7.5c-.706-.706-2.294-.706-3 0z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-progressive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-progressive.png
new file mode 100644
index 00000000..343d52f8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-progressive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-progressive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-progressive.svg
new file mode 100644
index 00000000..cd9e501a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-progressive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #347BFF }</style>
+ <g id="check">
+ <path d="M17 7.5L9.5 15 6 11.5 4.5 13l5 5L20 7.5c-.706-.706-2.294-.706-3 0z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/check.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check.png
new file mode 100644
index 00000000..1ea326df
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/check.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check.svg
new file mode 100644
index 00000000..cf7858ba
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="check">
+ <path d="M17 7.5L9.5 15 6 11.5 4.5 13l5 5L20 7.5c-.706-.706-2.294-.706-3 0z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.png
new file mode 100644
index 00000000..0e0d9c24
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg
new file mode 100644
index 00000000..085e6677
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #00AF89 }</style><circle cx="12" cy="12" r="6"></circle></svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.png
new file mode 100644
index 00000000..82c327a4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.svg
new file mode 100644
index 00000000..f5285c73
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style><circle cx="12" cy="12" r="6"></circle></svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.png
new file mode 100644
index 00000000..3bdc8e28
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg
new file mode 100644
index 00000000..436259e5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><circle cx="12" cy="12" r="6"></circle></svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr.png
new file mode 100644
index 00000000..ae1621c5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr.svg
new file mode 100644
index 00000000..28ba0cb5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M7 12h9v-1h-9v1zm0 2h9v-1h-9v1zm0 2h9v-1h-9v1zm4-9h-4v1h4v-1zm0 2h-4v1h4v-1zm0-4h-4v1h4v-1zm5-2h2v16h-10c-1.7 0-3-1.3-3-3v-13h8v7l1.5-2 1.5 2v-7z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl.png
new file mode 100644
index 00000000..4acaa0fb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl.svg
new file mode 100644
index 00000000..7625307c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g128">
+ <path d="M16 12h-9v-1h9v1zm0 2h-9v-1h9v1zm0 2h-9v-1h9v1zm-4-9h4v1h-4v-1zm0 2h4v1h-4v-1zm0-4h4v1h-4v-1zm-5-2h-2v16h10c1.7 0 3-1.3 3-3v-13h-8v7l-1.5-2-1.5 2v-7z" id="path130"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.png
new file mode 100644
index 00000000..b18e2e68
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.svg
new file mode 100644
index 00000000..55a26c97
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="clear">
+ <path id="circle-with-cross" d="M12 5c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm4 11l-1 1-3-3-3 3-1-1 3-3-3-3 1-1 3 3 3-3 1 1-3 3 3 3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.png
new file mode 100644
index 00000000..e62c52cd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.svg
new file mode 100644
index 00000000..1cf72670
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M12 5c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm3 12l-4-3v-6h2v5l1.7 1.2c1.3.9 1 1.9.3 2.8z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr-invert.png
new file mode 100644
index 00000000..6d8abc3b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr-invert.svg
new file mode 100644
index 00000000..ec44c925
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M18.4 8.1c.8-.8.8-2 0-2.8l-6.4 6.5-5.6-5.6-1.4 1.4 5.6 5.6-5 5c-.8.8-.8 2 0 2.8l6.4-6.4 5.6 5.6 1.4-1.4-5.6-5.6 5-5.1z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.png
new file mode 100644
index 00000000..ea65697c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.svg
new file mode 100644
index 00000000..4f0f64ec
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M18.4 8.1c.8-.8.8-2 0-2.8l-6.4 6.5-5.6-5.6-1.4 1.4 5.6 5.6-5 5c-.8.8-.8 2 0 2.8l6.4-6.4 5.6 5.6 1.4-1.4-5.6-5.6 5-5.1z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl-invert.png
new file mode 100644
index 00000000..004a5186
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl-invert.svg
new file mode 100644
index 00000000..b5ae392f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M5.6 8.1c-.8-.8-.8-2 0-2.8l6.4 6.5 5.6-5.6 1.4 1.4-5.6 5.6 5 5c.8.8.8 2 0 2.8l-6.4-6.4-5.6 5.6-1.4-1.4 5.6-5.6-5-5.1z" id="path140"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.png
new file mode 100644
index 00000000..1cb898d1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.svg
new file mode 100644
index 00000000..d9829d0e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M5.6 8.1c-.8-.8-.8-2 0-2.8l6.4 6.5 5.6-5.6 1.4 1.4-5.6 5.6 5 5c.8.8.8 2 0 2.8l-6.4-6.4-5.6 5.6-1.4-1.4 5.6-5.6-5-5.1z" id="path140"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.png
new file mode 100644
index 00000000..23c59835
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.svg
new file mode 100644
index 00000000..bc4ae943
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="code">
+ <path id="left-bracket" d="M4 12v-1h1c1 0 1 0 1-1v-2.386c0-.514.024-.896.073-1.142.054-.252.139-.463.257-.633.204-.279.473-.475.808-.584.335-.115.872-.255 1.835-.255h1.027v1h-.752c-.457 0-.77.191-.936.408-.167.215-.312.445-.312 1.068v1.857c0 .729-.041 1.18-.244 1.493-.2.307-.562.529-1.09.667.535.155.9.385 1.096.688.199.303.238.757.238 1.484v1.862c0 .619.145.848.312 1.062.166.22.479.407.936.407l.752.004v1h-1.027c-.963 0-1.5-.133-1.835-.248-.335-.109-.604-.307-.808-.591-.118-.165-.203-.374-.257-.625-.049-.253-.073-.636-.073-1.149v-2.387c0-1 0-1-1-1h-1z"/>
+ <use transform="matrix(-1 0 0 1 24 0)" id="right-bracket" width="24" height="24" xlink:href="#left-bracket"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.png
new file mode 100644
index 00000000..ee58c9a7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/code.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.svg
index a45ab1e3..32f140d9 100644
--- a/resources/lib/oojs-ui/images/icons/code.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
- <g id="code" opacity=".75">
+ <g id="code">
<path id="left-bracket" d="M4 12v-1h1c1 0 1 0 1-1v-2.386c0-.514.024-.896.073-1.142.054-.252.139-.463.257-.633.204-.279.473-.475.808-.584.335-.115.872-.255 1.835-.255h1.027v1h-.752c-.457 0-.77.191-.936.408-.167.215-.312.445-.312 1.068v1.857c0 .729-.041 1.18-.244 1.493-.2.307-.562.529-1.09.667.535.155.9.385 1.096.688.199.303.238.757.238 1.484v1.862c0 .619.145.848.312 1.062.166.22.479.407.936.407l.752.004v1h-1.027c-.963 0-1.5-.133-1.835-.248-.335-.109-.604-.307-.808-.591-.118-.165-.203-.374-.257-.625-.049-.253-.073-.636-.073-1.149v-2.387c0-1 0-1-1-1h-1z"/>
<use transform="matrix(-1 0 0 1 24 0)" id="right-bracket" width="24" height="24" xlink:href="#left-bracket"/>
</g>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.png
new file mode 100644
index 00000000..a9d0d33b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.svg
new file mode 100644
index 00000000..451e0fee
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="collapse">
+ <path id="arrow" d="M6.697 15.714l5.303-5.302 5.303 5.302 1.414-1.414-6.717-6.717-6.717 6.717z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.png
new file mode 100644
index 00000000..353ac798
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/collapse.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.svg
index c677e9e5..55aa8f8f 100644
--- a/resources/lib/oojs-ui/images/icons/collapse.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="collapse" opacity=".75">
+ <g id="collapse">
<path id="arrow" d="M6.697 15.714l5.303-5.302 5.303 5.302 1.414-1.414-6.717-6.717-6.717 6.717z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.png
new file mode 100644
index 00000000..0ed3528e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.svg
new file mode 100644
index 00000000..b6152fe9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="comment">
+ <path id="speech-bubble" d="M15 6h-6c-1.657 0-3 1.344-3 3v4c0 1.656 1.343 3 3 3v3l3-3h3c1.657 0 3-1.344 3-3v-4c0-1.656-1.343-3-3-3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment.png
new file mode 100644
index 00000000..265a3e41
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/comment.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment.svg
index 0348035b..0ae7e63f 100644
--- a/resources/lib/oojs-ui/images/icons/comment.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="comment" opacity=".75">
+ <g id="comment">
<path id="speech-bubble" d="M15 6h-6c-1.657 0-3 1.344-3 3v4c0 1.656 1.343 3 3 3v3l3-3h3c1.657 0 3-1.344 3-3v-4c0-1.656-1.343-3-3-3z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.png
new file mode 100644
index 00000000..07abcbe8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.svg
new file mode 100644
index 00000000..eb4c360d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M16 5h-12v12c0 1.6 1.3 3 3 3h12v-12c0-1.7-1.4-3-3-3zm-8.5 12c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm0-6c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm4 3c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm4 3c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5zm0-6c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.png
new file mode 100644
index 00000000..54c0af75
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.svg
new file mode 100644
index 00000000..e929fdb1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M7 5h12v12c0 1.6-1.3 3-3 3h-12v-12c0-1.7 1.4-3 3-3zm8.5 12c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5zm0-6c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5zm-4 3c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5zm-4 3c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5zm0-6c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5z" id="path150"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.png
new file mode 100644
index 00000000..9408199e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.svg
new file mode 100644
index 00000000..7bc1c228
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12 18l8-10h-16z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr.png
new file mode 100644
index 00000000..b63ca2da
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr.svg
new file mode 100644
index 00000000..d0d5bb5b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M16 11h-3v-7c-1.7 0-3 1.3-3 3v4h-3l4.5 5 4.5-5zm1 2v5h-10c-.6 0-1-.4-1-1v-4h-2v4c0 1.9 1.3 3 3 3h12v-7h-2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl.png
new file mode 100644
index 00000000..457ef94f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl.svg
new file mode 100644
index 00000000..9abb2ae4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g160">
+ <path d="M7 11h3v-7c1.7 0 3 1.3 3 3v4h3l-4.5 5-4.5-5zm-1 2v5h10c.6 0 1-.4 1-1v-4h2v4c0 1.9-1.3 3-3 3h-12v-7h2z" id="path162"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-invert.png
new file mode 100644
index 00000000..65b4c659
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-invert.svg
new file mode 100644
index 00000000..add25a45
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="Layer_3">
+ <path d="M17 2l-12 12-1 5 5-1 12-12c0-2-2-4-4-4zm-9.8 13.5c-.3-.3-.7-.6-1-.8 2.3-2.3 11.3-11.4 11.3-11.4.4.1.7.3 1 .7l-11.3 11.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-progressive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-progressive.png
new file mode 100644
index 00000000..ee2be2d8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-progressive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-progressive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-progressive.svg
new file mode 100644
index 00000000..bceb7c16
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-progressive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #347BFF }</style>
+ <g id="Layer_3">
+ <path d="M17 2l-12 12-1 5 5-1 12-12c0-2-2-4-4-4zm-9.8 13.5c-.3-.3-.7-.6-1-.8 2.3-2.3 11.3-11.4 11.3-11.4.4.1.7.3 1 .7l-11.3 11.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr.png
new file mode 100644
index 00000000..afaddc5a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr.svg
new file mode 100644
index 00000000..3972e070
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="Layer_3">
+ <path d="M17 2l-12 12-1 5 5-1 12-12c0-2-2-4-4-4zm-9.8 13.5c-.3-.3-.7-.6-1-.8 2.3-2.3 11.3-11.4 11.3-11.4.4.1.7.3 1 .7l-11.3 11.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-invert.png
new file mode 100644
index 00000000..2b311a9c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-invert.svg
new file mode 100644
index 00000000..339c8309
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="Layer_3">
+ <path d="M8 2l12 12 1 5-5-1-12-12c0-2 2-4 4-4zm9.8 13.5c.3-.3.7-.6 1-.8-2.3-2.3-11.3-11.4-11.3-11.4-.4.1-.7.3-1 .7l11.3 11.5z" id="path173"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-progressive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-progressive.png
new file mode 100644
index 00000000..8d36fa8a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-progressive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-progressive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-progressive.svg
new file mode 100644
index 00000000..d526fb4c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-progressive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #347BFF }</style>
+ <g id="Layer_3">
+ <path d="M8 2l12 12 1 5-5-1-12-12c0-2 2-4 4-4zm9.8 13.5c.3-.3.7-.6 1-.8-2.3-2.3-11.3-11.4-11.3-11.4-.4.1-.7.3-1 .7l11.3 11.5z" id="path173"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.png
new file mode 100644
index 00000000..4750795c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.svg
new file mode 100644
index 00000000..978b2fd1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="Layer_3">
+ <path d="M8 2l12 12 1 5-5-1-12-12c0-2 2-4 4-4zm9.8 13.5c.3-.3.7-.6 1-.8-2.3-2.3-11.3-11.4-11.3-11.4-.4.1-.7.3-1 .7l11.3 11.5z" id="path173"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr-invert.png
new file mode 100644
index 00000000..fe073925
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr-invert.svg
new file mode 100644
index 00000000..30d10218
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr-invert.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="Layer_2">
+ <g id="g184">
+ <path d="M21 4v-1s0-3-3-3-3 3-3 3v1h-1v6h8v-6zm-1.5 0h-3v-1s0-1.5 1.5-1.5c1.48.06 1.5 1.5 1.5 1.5zm-6.5 5.6l-6.8 6.9c-.3-.3-.7-.6-1-.8 1.4-1.4 5-5 7.8-7.9v-1.8l-9 9-1 5 5-1 8-8h-3z" id="path186"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.png
new file mode 100644
index 00000000..966bfcbc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.svg
new file mode 100644
index 00000000..7e376824
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="Layer_2">
+ <g id="g184">
+ <path d="M21 4v-1s0-3-3-3-3 3-3 3v1h-1v6h8v-6zm-1.5 0h-3v-1s0-1.5 1.5-1.5c1.48.06 1.5 1.5 1.5 1.5zm-6.5 5.6l-6.8 6.9c-.3-.3-.7-.6-1-.8 1.4-1.4 5-5 7.8-7.9v-1.8l-9 9-1 5 5-1 8-8h-3z" id="path186"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl-invert.png
new file mode 100644
index 00000000..ff54699b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl-invert.svg
new file mode 100644
index 00000000..0e975b59
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl-invert.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="Layer_2">
+ <g id="g184">
+ <path d="M4 4v-1s0-3 3-3 3 3 3 3v1h1v6h-8v-6zm1.5 0h3v-1s0-1.5-1.5-1.5c-1.48.06-1.5 1.5-1.5 1.5zm6.5 5.6l6.8 6.9c.3-.3.7-.6 1-.8-1.4-1.4-5-5-7.8-7.9v-1.8l9 9 1 5-5-1-8-8h3z" id="path186"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.png
new file mode 100644
index 00000000..961abe69
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.svg
new file mode 100644
index 00000000..0b4751d2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="Layer_2">
+ <g id="g184">
+ <path d="M4 4v-1s0-3 3-3 3 3 3 3v1h1v6h-8v-6zm1.5 0h3v-1s0-1.5-1.5-1.5c-1.48.06-1.5 1.5-1.5 1.5zm6.5 5.6l6.8 6.9c.3-.3.7-.6 1-.8-1.4-1.4-5-5-7.8-7.9v-1.8l9 9 1 5-5-1-8-8h3z" id="path186"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr-invert.png
new file mode 100644
index 00000000..3952442e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr-invert.svg
new file mode 100644
index 00000000..cc8b61f6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr-invert.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g196">
+ <g id="g198">
+ <path d="M14.9 2.8c.9 0 1.8.2 2.7.6.9.4 1.6.9 1.9 1.6-2.8.1-5 1.1-6.6 3.1l1.3 2-6.7-.3.5-6.8 1.7 2c1.8-1.5 3.5-2.2 5.2-2.2z" id="path200"/>
+ </g>
+ </g>
+ <g id="g204">
+ <path d="M15.2 11.1l-2.6-.1-5.4 5.5c-.3-.3-.7-.6-1-.8.9-.9 2.8-2.8 4.7-4.8h-1.8l-4.1 4.1-1 5 5-1 7.8-7.8-1.6-.1zm5.4-5.1c-1.7 0-3.2.5-4.4 1.4l-.9.9.8 1.3.9 1.4 4-4c0-.3-.1-.7-.2-1h-.2z" id="path206"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.png
new file mode 100644
index 00000000..fe8631ea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.svg
new file mode 100644
index 00000000..f346874e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g196">
+ <g id="g198">
+ <path d="M14.9 2.8c.9 0 1.8.2 2.7.6.9.4 1.6.9 1.9 1.6-2.8.1-5 1.1-6.6 3.1l1.3 2-6.7-.3.5-6.8 1.7 2c1.8-1.5 3.5-2.2 5.2-2.2z" id="path200"/>
+ </g>
+ </g>
+ <g id="g204">
+ <path d="M15.2 11.1l-2.6-.1-5.4 5.5c-.3-.3-.7-.6-1-.8.9-.9 2.8-2.8 4.7-4.8h-1.8l-4.1 4.1-1 5 5-1 7.8-7.8-1.6-.1zm5.4-5.1c-1.7 0-3.2.5-4.4 1.4l-.9.9.8 1.3.9 1.4 4-4c0-.3-.1-.7-.2-1h-.2z" id="path206"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl-invert.png
new file mode 100644
index 00000000..53469ce9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl-invert.svg
new file mode 100644
index 00000000..82018f0b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl-invert.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g196">
+ <g id="g198">
+ <path d="M10.1 2.8c-.9 0-1.8.2-2.7.6-.9.4-1.6.9-1.9 1.6 2.8.1 5 1.1 6.6 3.1l-1.3 2 6.7-.3-.5-6.8-1.7 2c-1.8-1.5-3.5-2.2-5.2-2.2z" id="path200"/>
+ </g>
+ </g>
+ <g id="g204">
+ <path d="M9.8 11.1l2.6-.1 5.4 5.5c.3-.3.7-.6 1-.8-.9-.9-2.8-2.8-4.7-4.8h1.8l4.1 4.1 1 5-5-1-7.8-7.8 1.6-.1zm-5.4-5.1c1.7 0 3.2.5 4.4 1.4l.9.9-.8 1.3-.9 1.4-4-4c0-.3.1-.7.2-1h.2z" id="path206"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.png
new file mode 100644
index 00000000..ca5596ee
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.svg
new file mode 100644
index 00000000..5b59d452
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g196">
+ <g id="g198">
+ <path d="M10.1 2.8c-.9 0-1.8.2-2.7.6-.9.4-1.6.9-1.9 1.6 2.8.1 5 1.1 6.6 3.1l-1.3 2 6.7-.3-.5-6.8-1.7 2c-1.8-1.5-3.5-2.2-5.2-2.2z" id="path200"/>
+ </g>
+ </g>
+ <g id="g204">
+ <path d="M9.8 11.1l2.6-.1 5.4 5.5c.3-.3.7-.6 1-.8-.9-.9-2.8-2.8-4.7-4.8h1.8l4.1 4.1 1 5-5-1-7.8-7.8 1.6-.1zm-5.4-5.1c1.7 0 3.2.5 4.4 1.4l.9.9-.8 1.3-.9 1.4-4-4c0-.3.1-.7.2-1h.2z" id="path206"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis-invert.png
new file mode 100644
index 00000000..1c876e33
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis-invert.svg
new file mode 100644
index 00000000..510cf3d2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis-invert.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g>
+ <g>
+ <path d="M8 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
+ </g>
+ <g>
+ <path d="M14 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
+ </g>
+ <g>
+ <path d="M20 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis.png
new file mode 100644
index 00000000..1e4050c9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis.svg
new file mode 100644
index 00000000..dd36a30d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ellipsis.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <g>
+ <path d="M8 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
+ </g>
+ <g>
+ <path d="M14 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
+ </g>
+ <g>
+ <path d="M20 13c0 .6-.2 1-.6 1.4-.4.4-.9.6-1.4.6-.6 0-1-.2-1.4-.6-.4-.4-.6-.9-.6-1.4s.2-1 .6-1.4c.4-.4.9-.6 1.4-.6s1 .2 1.4.6c.4.4.6.9.6 1.4z"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.png
new file mode 100644
index 00000000..05f7138b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.svg
new file mode 100644
index 00000000..a3cadb48
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="expand">
+ <path id="arrow" d="M17.303 8.283l-5.303 5.303-5.303-5.303-1.414 1.414 6.717 6.717 6.717-6.717z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand.png
new file mode 100644
index 00000000..9073d243
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/expand.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand.svg
index f41b9f9d..7666b41d 100644
--- a/resources/lib/oojs-ui/images/icons/expand.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="expand" opacity=".75">
+ <g id="expand">
<path id="arrow" d="M17.303 8.283l-5.303 5.303-5.303-5.303-1.414 1.414 6.717 6.717 6.717-6.717z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr-invert.png
new file mode 100644
index 00000000..3be50ba0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr-invert.svg
new file mode 100644
index 00000000..c1bad9e6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr-invert.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
+ <g id="external">
+ <path id="box" d="M2 2h3v1h-2v6h6v-2h1v3h-8z"/>
+ <path id="arrow" d="M6.211 2h3.789v3.789l-1.421-1.421-2.132 2.132-.947-.947 2.132-2.132z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr.png
new file mode 100644
index 00000000..10927e16
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr.svg
new file mode 100644
index 00000000..827bc1b1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+ <g id="external">
+ <path id="box" d="M2 2h3v1h-2v6h6v-2h1v3h-8z"/>
+ <path id="arrow" d="M6.211 2h3.789v3.789l-1.421-1.421-2.132 2.132-.947-.947 2.132-2.132z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl-invert.png
new file mode 100644
index 00000000..eaeaf6ee
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl-invert.svg
new file mode 100644
index 00000000..f448c879
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl-invert.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
+ <g id="external">
+ <path id="box" d="M7 3h2v6h-6v-2h-1v3h8v-8h-3z"/>
+ <path id="arrow" d="M2 5.789l1.421-1.421 2.132 2.132.947-.947-2.132-2.132 1.421-1.421h-3.789z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl.png
new file mode 100644
index 00000000..7a3454e9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl.svg
new file mode 100644
index 00000000..c375ca0f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+ <g id="external">
+ <path id="box" d="M7 3h2v6h-6v-2h-1v3h8v-8h-3z"/>
+ <path id="arrow" d="M2 5.789l1.421-1.421 2.132 2.132.947-.947-2.132-2.132 1.421-1.421h-3.789z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.png
new file mode 100644
index 00000000..26accd8c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.svg
new file mode 100644
index 00000000..fa3bc3c1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g4">
+ <path d="M12 8c-5 0-11 6-11 6s6 6 11 6 11-6 11-6-6-6-11-6zm0 10c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z" id="path6"/>
+ <circle cx="12" cy="14" r="2" id="circle8"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.png
new file mode 100644
index 00000000..301bf8cb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.svg
new file mode 100644
index 00000000..fa1167df
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M19.4 12.7c.7-.8 1.2-1.7 1.4-2.7h-1.6c-.9 2.5-3.9 4.4-7.7 4.6h-.1c-3.7-.2-6.8-2.1-7.7-4.6h-1.5c.2 1 .8 1.9 1.4 2.7l-2 2 .7.7 2-2c.8.6 1.7 1.2 2.7 1.7l-1 2.8.9.3 1-2.8c1 .3 2 .6 3.1.6v3h1v-3c1.1-.1 2.2-.3 3.1-.6l1 2.8.9-.3-1-2.8c1-.4 1.9-1 2.6-1.7l2 2 .7-.7-1.9-2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.png
new file mode 100644
index 00000000..4336892a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.svg
new file mode 100644
index 00000000..f8578cf8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="find">
+ <path id="magnifying-glass" d="m 13.65625,11 c -1.921,0 -3.5,1.54775 -3.5,3.46875 0,1.92 1.579,3.5 3.5,3.5 0.749,0 1.432,-0.25225 2,-0.65625 l 0.09375,0.15625 2.375,2.375 c 0.19,0.189 0.53425,0.15325 0.78125,-0.09375 0.247,-0.247 0.314,-0.59125 0.125,-0.78125 l -2.375,-2.375 L 16.46875,16.5 C 16.87175,15.934 17.125,15.21775 17.125,14.46875 17.124,12.54875 15.57525,11 13.65625,11 z m 0,1.65625 c 1.011306,0 1.8125,0.801194 1.8125,1.8125 0,1.011306 -0.801194,1.84375 -1.8125,1.84375 -1.011306,0 -1.84375,-0.832444 -1.84375,-1.84375 0,-1.011306 0.832444,-1.8125 1.84375,-1.8125 z" />
+ <path id="text" d="M 6,5 6,7 16,7 16,5 6,5 z m 0,3 0,2 11,0 0,-2 -11,0 z m 0,3 0,2 3.53125,0 c 0.2825289,-0.797203 0.786096,-1.486208 1.4375,-2 L 6,11 z m 0,3 0,2 3.53125,0 C 9.3537004,15.520243 9.25,15.010236 9.25,14.46875 9.25,14.309811 9.2962033,14.154621 9.3125,14 L 6,14 z" />
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.png
new file mode 100644
index 00000000..f492c791
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.svg
new file mode 100644
index 00000000..2a1e9c6f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="find">
+ <path id="magnifying-glass" d="m 11.343828,11.000025 c 1.921,0 3.5,1.54775 3.5,3.46875 0,1.92 -1.579,3.5 -3.5,3.5 -0.749,0 -1.432,-0.25225 -2,-0.65625 l -0.09375,0.15625 -2.375,2.375 c -0.19,0.189 -0.53425,0.15325 -0.78125,-0.09375 -0.247,-0.247 -0.314,-0.59125 -0.125,-0.78125 l 2.375,-2.375 0.1875,-0.09375 c -0.403,-0.566 -0.65625,-1.28225 -0.65625,-2.03125 10e-4,-1.92 1.54975,-3.46875 3.46875,-3.46875 z m 0,1.65625 c -1.011306,0 -1.8125,0.801194 -1.8125,1.8125 0,1.011306 0.801194,1.84375 1.8125,1.84375 1.011306,0 1.84375,-0.832444 1.84375,-1.84375 0,-1.011306 -0.832444,-1.8125 -1.84375,-1.8125 z" />
+ <path id="text" d="M 19,5 19,7 9,7 9,5 z m 0,3 0,2 -11,0 0,-2 z m 0,3 0,2 -3.53125,0 c -0.282529,-0.797203 -0.786096,-1.486208 -1.4375,-2 z m 0,3 0,2 -3.53125,0 C 15.6463,15.520243 15.75,15.010236 15.75,14.46875 15.75,14.309811 15.703797,14.154621 15.6875,14 z" />
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr-invert.png
new file mode 100644
index 00000000..b9ad2b8f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr-invert.svg
new file mode 100644
index 00000000..37ddb247
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M14 6.5v-1.5c-1.4-1.5-5.2-1.2-6 0v-1h-1v15h1v-7c.8-.8 3.4-.9 5-.5v1.5c1.2 1.5 4.3 1.2 5 0v-7c-.7.7-2.7.9-4 .5z" id="path216"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.png
new file mode 100644
index 00000000..63ceaafb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.svg
new file mode 100644
index 00000000..6e81d2bc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M14 6.5v-1.5c-1.4-1.5-5.2-1.2-6 0v-1h-1v15h1v-7c.8-.8 3.4-.9 5-.5v1.5c1.2 1.5 4.3 1.2 5 0v-7c-.7.7-2.7.9-4 .5z" id="path216"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl-invert.png
new file mode 100644
index 00000000..da059cfb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl-invert.svg
new file mode 100644
index 00000000..4875a443
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M11 6.5v-1.5c1.4-1.5 5.2-1.2 6 0v-1h1v15h-1v-7c-.8-.8-3.4-.9-5-.5v1.5c-1.2 1.5-4.3 1.2-5 0v-7c.7.7 2.7.9 4 .5z" id="path216"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.png
new file mode 100644
index 00000000..80835c0c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.svg
new file mode 100644
index 00000000..4b743aac
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M11 6.5v-1.5c1.4-1.5 5.2-1.2 6 0v-1h1v15h-1v-7c-.8-.8-3.4-.9-5-.5v1.5c-1.2 1.5-4.3 1.2-5 0v-7c.7.7 2.7.9 4 .5z" id="path216"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr-invert.png
new file mode 100644
index 00000000..fd7f2ae8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr-invert.svg
new file mode 100644
index 00000000..dcea1eb7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr-invert.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g2990">
+ <g id="Layer_1">
+ <path id="path227" d="M14 6.5v-1.5c-1.4-1.5-5.2-1.2-6 0v-1h-1v15h1v-7c.8-.8 3.4-.9 5-.5v1.5c1.2 1.5 4.3 1.2 5 0v-7c-.7.7-2.7.9-4 .5z"/>
+ </g>
+ <g id="Layer_2">
+ <g id="g230">
+ <path id="path232" d="M17.997 1.989l.99.99-15.98 15.98-.99-.99z"/>
+ </g>
+ <g id="g234">
+ <path id="path236" d="M16.999 1.016l.99.99-15.98 15.98-.99-.99z" fill="#fff"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.png
new file mode 100644
index 00000000..fff89fe8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.svg
new file mode 100644
index 00000000..49cdb7a2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g2990">
+ <g id="Layer_1">
+ <path id="path227" d="M14 6.5v-1.5c-1.4-1.5-5.2-1.2-6 0v-1h-1v15h1v-7c.8-.8 3.4-.9 5-.5v1.5c1.2 1.5 4.3 1.2 5 0v-7c-.7.7-2.7.9-4 .5z"/>
+ </g>
+ <g id="Layer_2">
+ <g id="g230">
+ <path id="path232" d="M17.997 1.989l.99.99-15.98 15.98-.99-.99z"/>
+ </g>
+ <g id="g234">
+ <path id="path236" d="M16.999 1.016l.99.99-15.98 15.98-.99-.99z" fill="#fff"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl-invert.png
new file mode 100644
index 00000000..1ae130d1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl-invert.svg
new file mode 100644
index 00000000..d6ffceaa
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl-invert.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g2990">
+ <g id="Layer_1">
+ <path id="path227" d="M11 6.5v-1.5c1.4-1.5 5.2-1.2 6 0v-1h1v15h-1v-7c-.8-.8-3.4-.9-5-.5v1.5c-1.2 1.5-4.3 1.2-5 0v-7c.7.7 2.7.9 4 .5z"/>
+ </g>
+ <g id="Layer_2">
+ <g id="g230">
+ <path id="path232" d="M7.003 1.989l-.99.99 15.98 15.98.99-.99z"/>
+ </g>
+ <g id="g234">
+ <path id="path236" d="M8.001 1.016l-.99.99 15.98 15.98.99-.99z" fill="#fff"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.png
new file mode 100644
index 00000000..89674cc7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.svg
new file mode 100644
index 00000000..e470de42
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.svg
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g2990">
+ <g id="Layer_1">
+ <path id="path227" d="M11 6.5v-1.5c1.4-1.5 5.2-1.2 6 0v-1h1v15h-1v-7c-.8-.8-3.4-.9-5-.5v1.5c-1.2 1.5-4.3 1.2-5 0v-7c.7.7 2.7.9 4 .5z"/>
+ </g>
+ <g id="Layer_2">
+ <g id="g230">
+ <path id="path232" d="M7.003 1.989l-.99.99 15.98 15.98.99-.99z"/>
+ </g>
+ <g id="g234">
+ <path id="path236" d="M8.001 1.016l-.99.99 15.98 15.98.99-.99z" fill="#fff"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.png
new file mode 100644
index 00000000..163465e1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg
new file mode 100644
index 00000000..63e0b1aa
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M2 5v15h20v-15h-20zm15 11h-9c-.6 0-1-.4-1-1v-6h3l2 1h5v6z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.png
new file mode 100644
index 00000000..4856f62c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg
new file mode 100644
index 00000000..25bec742
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M22 5v15h-20v-15h20zm-15 11h9c.6 0 1-.4 1-1v-6h-3l-2 1h-5v6z" id="path246"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.png
new file mode 100644
index 00000000..df174d62
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.svg
new file mode 100644
index 00000000..191584eb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M11 13l-6-7h15l-6 7v7c-1.7 0-3-1.3-3-3v-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl.png
new file mode 100644
index 00000000..1204eb1e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl.svg
new file mode 100644
index 00000000..45f2f642
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g256">
+ <path d="M14 13l6-7h-15l6 7v7c1.7 0 3-1.3 3-3v-4z" id="path258"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart.png
new file mode 100644
index 00000000..0bd2124a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart.svg
new file mode 100644
index 00000000..6433201a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M15 7c-2 0-3 2-3 2s-1-2-3-2c-2.5 0-4 2-4 4 0 4 5 5 7 8 2-3 7-4 7-8 0-2-1.5-4-4-4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr-invert.png
new file mode 100644
index 00000000..185c1a27
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr-invert.svg
new file mode 100644
index 00000000..3670661a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr-invert.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="help">
+ <path id="circle" d="M12.001 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 5.476 4.438 9.914 9.916 9.914 5.476 0 9.914-4.438 9.914-9.914 0-5.478-4.438-9.916-9.914-9.916zm.001 18c-4.465 0-8.084-3.619-8.084-8.083 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083z"/>
+ <g id="question-mark">
+ <path id="top" d="M11.766 6.688c-2.5 0-3.219 2.188-3.219 2.188l1.411.854s.298-.791.901-1.229c.516-.375 1.625-.625 2.219.125.701.885-.17 1.587-1.078 2.719-.953 1.186-1 3.655-1 3.655h1.969s.135-2.318 1.041-3.381c.603-.707 1.443-1.338 1.443-2.494s-1.187-2.437-3.687-2.437z"/>
+ <path id="bottom" d="M11 16h2v2h-2z"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.png
new file mode 100644
index 00000000..b80df009
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/help.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.svg
index ce129a74..bb2545c5 100644
--- a/resources/lib/oojs-ui/images/icons/help.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="help" opacity=".75">
+ <g id="help">
<path id="circle" d="M12.001 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 5.476 4.438 9.914 9.916 9.914 5.476 0 9.914-4.438 9.914-9.914 0-5.478-4.438-9.916-9.914-9.916zm.001 18c-4.465 0-8.084-3.619-8.084-8.083 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083z"/>
<g id="question-mark">
<path id="top" d="M11.766 6.688c-2.5 0-3.219 2.188-3.219 2.188l1.411.854s.298-.791.901-1.229c.516-.375 1.625-.625 2.219.125.701.885-.17 1.587-1.078 2.719-.953 1.186-1 3.655-1 3.655h1.969s.135-2.318 1.041-3.381c.603-.707 1.443-1.338 1.443-2.494s-1.187-2.437-3.687-2.437z"/>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl-invert.png
new file mode 100644
index 00000000..dfb9c031
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl-invert.svg
new file mode 100644
index 00000000..203f8f9b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl-invert.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="help">
+ <path id="circle" d="M11.999 2.085c5.478 0 9.916 4.438 9.916 9.916 0 5.476-4.438 9.914-9.916 9.914-5.476 0-9.914-4.438-9.914-9.914 0-5.478 4.438-9.916 9.914-9.916zm-.001 18c4.465 0 8.084-3.619 8.084-8.083 0-4.465-3.619-8.084-8.084-8.084-4.464 0-8.083 3.619-8.083 8.084 0 4.464 3.619 8.083 8.083 8.083z"/>
+ <g id="question-mark">
+ <path id="top" d="M12.234 6.688c2.5 0 3.219 2.188 3.219 2.188l-1.411.854s-.298-.791-.901-1.229c-.516-.375-1.625-.625-2.219.125-.701.885.17 1.587 1.078 2.719.953 1.186 1 3.655 1 3.655h-1.969s-.135-2.318-1.041-3.381c-.603-.707-1.443-1.338-1.443-2.494 0-1.156 1.187-2.437 3.687-2.437z"/>
+ <path id="bottom" d="M13 16h-2v2h2z"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.png
new file mode 100644
index 00000000..62f3d21a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.svg
new file mode 100644
index 00000000..99c7f842
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="help">
+ <path id="circle" d="M11.999 2.085c5.478 0 9.916 4.438 9.916 9.916 0 5.476-4.438 9.914-9.916 9.914-5.476 0-9.914-4.438-9.914-9.914 0-5.478 4.438-9.916 9.914-9.916zm-.001 18c4.465 0 8.084-3.619 8.084-8.083 0-4.465-3.619-8.084-8.084-8.084-4.464 0-8.083 3.619-8.083 8.084 0 4.464 3.619 8.083 8.083 8.083z"/>
+ <g id="question-mark">
+ <path id="top" d="M12.234 6.688c2.5 0 3.219 2.188 3.219 2.188l-1.411.854s-.298-.791-.901-1.229c-.516-.375-1.625-.625-2.219.125-.701.885.17 1.587 1.078 2.719.953 1.186 1 3.655 1 3.655h-1.969s-.135-2.318-1.041-3.381c-.603-.707-1.443-1.338-1.443-2.494 0-1.156 1.187-2.437 3.687-2.437z"/>
+ <path id="bottom" d="M13 16h-2v2h2z"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.png
new file mode 100644
index 00000000..24d3e17f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.svg
new file mode 100644
index 00000000..fb613827
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="history">
+ <path id="clock-hands" d="M17.26 15.076s-2.385-1.935-4.005-3.062c.72-2.397 1.702-6.559 1.702-6.559s-4.35 5.363-4.877 6.699c-.463 1.168 1.459 2.209 2.346 1.678 1.9.551 4.834 1.244 4.834 1.244z"/>
+ <path id="arrow" d="M12.086 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 1.783.476 3.454 1.301 4.898l-2.223 2.04h5.688v-5.219l-2.066 1.896c-.55-1.088-.866-2.312-.866-3.615 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083-1.145 0-2.228-.247-3.213-.678l-.833 1.634c1.235.557 2.602.874 4.045.874 5.476 0 9.914-4.438 9.914-9.914-.001-5.477-4.439-9.915-9.915-9.915z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.png
new file mode 100644
index 00000000..f5a7d36e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/history.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.svg
index 91e072f5..35f15afe 100644
--- a/resources/lib/oojs-ui/images/icons/history.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="history" opacity=".75">
+ <g id="history">
<path id="clock-hands" d="M17.26 15.076s-2.385-1.935-4.005-3.062c.72-2.397 1.702-6.559 1.702-6.559s-4.35 5.363-4.877 6.699c-.463 1.168 1.459 2.209 2.346 1.678 1.9.551 4.834 1.244 4.834 1.244z"/>
<path id="arrow" d="M12.086 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 1.783.476 3.454 1.301 4.898l-2.223 2.04h5.688v-5.219l-2.066 1.896c-.55-1.088-.866-2.312-.866-3.615 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083-1.145 0-2.228-.247-3.213-.678l-.833 1.634c1.235.557 2.602.874 4.045.874 5.476 0 9.914-4.438 9.914-9.914-.001-5.477-4.439-9.915-9.915-9.915z"/>
</g>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr.png
new file mode 100644
index 00000000..58bf5643
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr.svg
new file mode 100644
index 00000000..bebe0a9e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M20 18l-4-4-2 2-4-4-2 1-4 5h16zm2-13v15h-20v-15h20z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl.png
new file mode 100644
index 00000000..73ee31a3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl.svg
new file mode 100644
index 00000000..88e0e3c0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g278">
+ <path d="M4 18l4-4 2 2 4-4 2 1 4 5h-16zm-2-13v15h20v-15h-20z" id="path280"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.png
new file mode 100644
index 00000000..7ed8b7e7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.svg
new file mode 100644
index 00000000..300e4b15
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M17 12v-4h-4v-3h-13v15h20v-8h-3zm-15 6l4-5 2-1 4 4 2-2 4 4h-16z"/>
+ <g>
+ <path d="M24 5h-4v-4h-2v4h-4v2h4v4h2v-4h4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.png
new file mode 100644
index 00000000..74b6ef39
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.svg
new file mode 100644
index 00000000..70e32486
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M7 12v-4h4v-3h13v15h-20v-8h3zm15 6l-4-5-2-1-4 4-2-2-4 4h16z" id="path290"/>
+ <g id="g292">
+ <path d="M0 5h4v-4h2v4h4v2h-4v4h-2v-4h-4z" id="path294"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.png
new file mode 100644
index 00000000..c636a8df
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.svg
new file mode 100644
index 00000000..8cec9f5a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M19.5 4h-3v-1s0-1.5 1.5-1.5c1.5.06 1.5 1.5 1.5 1.5zm1.5 0v-1s0-3-3-3-3 3-3 3v1h-1v6h8v-6zm-8 7v-6h-11v15h20v-9zm-9 7l4-5 2-1 4 4 2-2 4 4z" id="path304"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.png
new file mode 100644
index 00000000..59439aa8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.svg
new file mode 100644
index 00000000..6bb78f71
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M4.5 4h3v-1s0-1.5-1.5-1.5c-1.5.06-1.5 1.5-1.5 1.5zm-1.5 0v-1s0-3 3-3 3 3 3 3v1h1v6h-8v-6zm8 7v-6h11v15h-20v-9zm9 7l-4-5-2-1-4 4-2-2-4 4z" id="path304"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr.png
new file mode 100644
index 00000000..daf4257a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr.svg
new file mode 100644
index 00000000..ada33959
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M10 8h9v2h-9v-2zm0 3h9v2h-9v-2zm0 3h6v2h-6v-2zm11-8h-18v-2h18v2zm0 14h-18v-2h18v2zm-18-12v8l5-4-5-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl.png
new file mode 100644
index 00000000..6ebe883d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl.svg
new file mode 100644
index 00000000..9afedbbd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g314">
+ <path d="M14 8h-9v2h9v-2zm0 3h-9v2h9v-2zm0 3h-6v2h6v-2zm-11-8h18v-2h-18v2zm0 14h18v-2h-18v2zm18-12v8l-5-4 5-4z" id="path316"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.png
new file mode 100644
index 00000000..83b00a27
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.svg
new file mode 100644
index 00000000..04cd8890
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="info">
+ <path id="circled-i" d="M11.499 17c-3.036 0-5.499-2.464-5.499-5.5 0-3.037 2.462-5.5 5.499-5.5 3.037 0 5.501 2.462 5.501 5.5 0 3.036-2.464 5.5-5.501 5.5zm.002-12c-3.591 0-6.501 2.91-6.501 6.5s2.91 6.5 6.501 6.5c3.588 0 6.499-2.911 6.499-6.5s-2.911-6.5-6.499-6.5zM12 10v4h1v1h-3v-1h1v-3h-1v-1zM11 8h1v1h-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/info.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info.png
new file mode 100644
index 00000000..eb0fb468
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/info.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info.svg
index 9ba57d7a..4bdefd46 100644
--- a/resources/lib/oojs-ui/images/icons/info.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info.svg
@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
- <g id="info" opacity=".75">
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="info">
<path id="circled-i" d="M11.499 17c-3.036 0-5.499-2.464-5.499-5.5 0-3.037 2.462-5.5 5.499-5.5 3.037 0 5.501 2.462 5.501 5.5 0 3.036-2.464 5.5-5.501 5.5zm.002-12c-3.591 0-6.501 2.91-6.501 6.5s2.91 6.5 6.501 6.5c3.588 0 6.499-2.911 6.499-6.5s-2.911-6.5-6.499-6.5zM12 10v4h1v1h-3v-1h1v-3h-1v-1zM11 8h1v1h-1z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.png
new file mode 100644
index 00000000..97927a84
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.svg
new file mode 100644
index 00000000..0833f84f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="insert">
+ <path d="M13 5h-2v6h-6v2h6v6h2v-6h6v-2h-6z" id="plus"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.png
new file mode 100644
index 00000000..a81e803d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.svg
new file mode 100644
index 00000000..a0e66bff
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-a">
+ <path id="a" d="M14.667 6h-1.372l-7 12h1.705l2.333-4h4l.667 4h1.667l-2-12zm-3.75 7l2.527-4.333.723 4.333h-3.25z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem.png
new file mode 100644
index 00000000..7cf774fa
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg
new file mode 100644
index 00000000..d4bff1be
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-arab-keheh-jeem">
+ <path id="arab-keheh-jeem" d="M18.125 5.844c-1.695.555-3.297 1.162-4.594 1.938-.49.299-.774.712-.875 1.125-.064.263-.035.572.063.781.189.405.539.574.844.813l.094-.125.531.625c.14.164.343.513.469.938.137.463.08.725 0 1.125h-3.438c-.338 0-.592.007-.766-.02-.339-.053-.256-.208-.234-.34.332-.127.564-.173.938-.141.29-.494.593-.885.906-1.313-.98.037-1.878.015-2.688-.094-.346-.047-.698-.186-1.094-.156-.357.026-.768.239-1.031.719-.246.448-.434.839-.656 1.281l.75-.469c.23-.142.484-.227.719-.219.157.005.275.054.406.094-.231.205-.509.402-.719.563-.301.26-.702.688-.906 1-.403.615-.694 1.084-.875 1.781-.179.689.004 1.339.469 1.75.426.376.846.519 1.281.563.65.065 1.205.093 2-.188.657-.231 1.021-.553 1.5-.969-.883.11-1.817.089-2.531.031-.871-.07-1.268-.384-1.469-.594-.271-.283-.307-.64-.156-1.219.036-.141.097-.323.25-.531.168-.228.364-.435.594-.656.451-.436 1.011-.737 1.461-.938-.045.206-.107.443-.055.688.049.229.248.379.438.469.259.122.506.155.688.156 1.421.011 2.862 0 4.281 0 .247 0 .452-.163.594-.375.139-.208.249-.481.344-.844.131-.499.094-1.062-.094-1.625-.182-.543-.418-1.009-.719-1.406-.335-.443-.674-.829-1-1.219 1.257-.815 2.716-1.239 3.969-1.688.121-.452.224-.926.313-1.313zm-9.469 8.438c-.262.394-.584.691-.875 1 .375.286.748.556 1.094.813.335-.303.626-.674.875-.969-.39-.268-.771-.588-1.094-.844z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem.png
new file mode 100644
index 00000000..e8f2b620
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem.svg
new file mode 100644
index 00000000..bfbc9bf5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-arab-meem">
+ <path id="arab-meem" d="M16 9.729l-.93 2.19h-4.663c-.479 0-.857.122-1.135.367l-.061.11c-.184 2.016-.502 3.558-.955 4.627-.272.641-.633 1.252-1.082 1.833-.177.226-.219.186-.126-.119l.142-.504.17-.669.234-.87.002-.009.202-1.045.258-1.411.353-1.906c.191-.312.424-.638.699-.98.276-.342.589-.706.94-1.09.129-.092.697-.18 1.705-.266 1.05-.086 1.638-.183 1.765-.293l.065-.128c.007-.11-.011-.241-.054-.394-.043-.153-.12-.327-.231-.522-.22-.428-.438-.641-.654-.641-.294 0-.915.269-1.864.806-.359.208-.376.125-.051-.247 1.558-1.71 2.708-2.566 3.45-2.566.383 0 .671.131.863.394.135.195.25.599.344 1.21l.203 1.2c.106.586.242.895.409.925"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha.png
new file mode 100644
index 00000000..4d4178ac
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha.svg
new file mode 100644
index 00000000..63de0f6c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-armn-sha">
+ <path id="armn-sha" d="M11.564 7.678c-.268-.13-.578-.22-.93-.268-.35-.047-.75-.07-1.197-.07h-1.11L8.586 6h1.724c.558 0 1.042.032 1.45.095.416.063.794.173 1.136.33l4.483 2.033-.324 1.67-2.624-1.165c-.126-.058-.27-.103-.433-.134-.164-.038-.356-.057-.576-.057-.583 0-1.137.095-1.663.284-.524.19-1 .46-1.425.812-.42.35-.777.78-1.072 1.283-.294.504-.504 1.074-.63 1.71-.242 1.255-.152 2.21.268 2.868.426.652 1.19.978 2.294.978.55 0 1.045-.08 1.48-.237.437-.156.815-.377 1.136-.66.326-.29.59-.633.796-1.033.21-.4.362-.84.457-1.323l.11-.56h1.6l-.12.59c-.13.674-.356 1.288-.676 1.845-.32.55-.725 1.026-1.214 1.425-.488.394-1.053.7-1.694.922-.642.215-1.343.323-2.105.323-.767 0-1.434-.113-2-.34-.568-.225-1.025-.553-1.372-.984-.347-.436-.573-.97-.678-1.607-.105-.637-.078-1.364.08-2.184.125-.66.346-1.273.66-1.835.316-.567.697-1.066 1.144-1.496.445-.436.944-.794 1.496-1.072.55-.284 1.13-.475 1.733-.575l-.466-.23"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.png
new file mode 100644
index 00000000..fc6133ca
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.svg
new file mode 100644
index 00000000..b468deac
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-c">
+ <path id="c" d="M15.008 13.718l1.481.214c-.468 1.34-1.15 2.354-2.046 3.04-.896.686-1.901 1.029-3.015 1.029-1.359 0-2.438-.43-3.237-1.29-.794-.86-1.191-2.092-1.191-3.697 0-2.09.606-3.818 1.817-5.185 1.079-1.219 2.42-1.828 4.023-1.828 1.186 0 2.145.33 2.878.989.738.66 1.165 1.546 1.282 2.66l-1.397.135c-.148-.839-.453-1.464-.916-1.876-.458-.417-1.051-.625-1.779-.625-1.369 0-2.476.631-3.321 1.892-.733 1.087-1.099 2.377-1.099 3.871 0 1.193.282 2.103.847 2.731.565.628 1.3.942 2.206.942.774 0 1.473-.261 2.099-.784.626-.522 1.081-1.261 1.366-2.216"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.png
new file mode 100644
index 00000000..1711ef95
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.svg
new file mode 100644
index 00000000..92a834d9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-d">
+ <path id="d" d="M7 18l2.462-12h3.557c.853 0 1.505.063 1.955.188.644.169 1.194.472 1.65.909.456.431.799.971 1.03 1.621.231.649.346 1.378.346 2.186 0 .966-.145 1.847-.435 2.644-.284.791-.66 1.49-1.127 2.095-.461.6-.947 1.072-1.456 1.416-.504.338-1.102.589-1.794.753-.526.126-1.172.188-1.939.188h-4.249m1.859-1.359h1.867c.842 0 1.591-.079 2.245-.237.408-.098.756-.243 1.046-.434.381-.246.727-.57 1.038-.974.408-.535.732-1.143.974-1.825.247-.688.37-1.468.37-2.341 0-.971-.166-1.716-.499-2.235-.333-.524-.756-.87-1.271-1.04-.381-.126-.974-.188-1.778-.188h-1.85l-1.907 9.274"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.png
new file mode 100644
index 00000000..f5b44d9e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.svg
new file mode 100644
index 00000000..66a5ef5d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-e">
+ <path id="e" d="M7 18l2.474-12h8.526l-.282 1.367h-6.947l-.75 3.633h6.09l-.282 1.367h-6.09l-.877 4.274h7.438l-.282 1.359h-9.018"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan.png
new file mode 100644
index 00000000..e728cd7b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan.svg
new file mode 100644
index 00000000..3398904d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-geor-kan">
+ <path id="geor-kan" d="M15.057 14.663c-.441 2.225-1.834 3.337-4.178 3.337-1.919 0-2.879-.787-2.879-2.36 0-.298.036-.624.108-.977.083-.431.245-.836.488-1.217l1.241.605-.207.613c-.055.259-.083.497-.083.712 0 .972.521 1.458 1.564 1.458 1.307 0 2.101-.723 2.383-2.17l.058-.331c.044-.221.066-.425.066-.613 0-.928-.546-1.391-1.638-1.391h-1.117l.248-1.259h1.117c1.202-.005 1.908-.552 2.118-1.64.039-.182.058-.356.058-.522 0-1.143-.899-1.714-2.697-1.714l.232-1.193c2.708 0 4.062.875 4.062 2.625 0 .248-.028.516-.083.803-.204 1.093-1.051 1.825-2.54 2.195l-.033.166c1.23.199 1.845.823 1.845 1.872 0 .21-.025.433-.074.671l-.058.331"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.png
new file mode 100644
index 00000000..3c6b3c1b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.svg
new file mode 100644
index 00000000..93bec5a6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-i">
+ <path id="i" d="M12.5 17.999l.249-.994h-1.5l2.509-10.037h1.5l.242-.967h-5l-.242.967h1.5l-2.509 10.037h-1.5l-.249.994z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.png
new file mode 100644
index 00000000..4f87e9ae
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.svg
new file mode 100644
index 00000000..d4831549
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-k">
+ <path id="k" d="M12.018 10.652l4.982-4.652h-2l-5.309 5.234 1.309-5.234h-1.5l-3 12h1.5l1.173-4.693 1.54-1.438c.287 4.131 3.287 6.131 3.287 6.131h2s-4-2-3.982-7.348z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.png
new file mode 100644
index 00000000..4fc10c50
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.svg
new file mode 100644
index 00000000..4f6364cb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="italic-s">
+ <path id="s" d="M16.474 6.589l-.302 1.526c-.522-.279-1.041-.488-1.557-.628-.511-.145-1.007-.217-1.487-.217-.935 0-1.679.204-2.231.612-.553.408-.829.95-.829 1.627 0 .372.101.658.302.86.207.196.733.408 1.58.635l.937.232c1.059.274 1.795.622 2.208 1.046.413.418.62 1.007.62 1.766 0 1.167-.46 2.117-1.379 2.851-.914.733-2.12 1.1-3.618 1.1-.615 0-1.232-.062-1.852-.186-.62-.119-1.242-.302-1.867-.55l.318-1.611c.573.356 1.147.625 1.72.806.578.181 1.154.271 1.728.271.976 0 1.759-.217 2.347-.651.589-.434.883-.999.883-1.697 0-.465-.119-.816-.356-1.054-.232-.243-.736-.462-1.511-.658l-.937-.24c-1.069-.279-1.8-.599-2.192-.961-.387-.367-.581-.878-.581-1.534 0-1.152.442-2.094 1.325-2.828.888-.739 2.043-1.108 3.463-1.108.553 0 1.1.049 1.642.147.542.098 1.085.245 1.627.442"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.png
new file mode 100644
index 00000000..b08c1d4b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.svg
new file mode 100644
index 00000000..c7e16033
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M16 9v-1h-6v1h6zm-2 2v-1h-4v1h4zm-8-6h1v16h-1v-16zm2 0h10v13c0 1.7-1.3 3-3 3h-7v-16z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.png
new file mode 100644
index 00000000..31dbb886
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.svg
new file mode 100644
index 00000000..2d16be37
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M8 9v-1h6v1h-6zm2 2v-1h4v1h-4zm8-6h-1v16h1v-16zm-2 0h-10v13c0 1.7 1.3 3 3 3h7v-16z" id="path326"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.png
new file mode 100644
index 00000000..ba9ce73d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.svg
new file mode 100644
index 00000000..8dfb89ae
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M14.5 4c-3 0-5.5 2.5-5.5 5.5 0 1 .3 1.9.7 2.8l-5.7 5.7v2h4v-2h2v-2h2l1.2-1.2c.4.1.9.2 1.3.2 3 0 5.5-2.5 5.5-5.5s-2.5-5.5-5.5-5.5zm1.5 5c-.8 0-1.5-.7-1.5-1.5s.7-1.5 1.5-1.5 1.5.7 1.5 1.5-.7 1.5-1.5 1.5z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.png
new file mode 100644
index 00000000..65ed300a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.svg
new file mode 100644
index 00000000..06392874
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M9.5 4c3 0 5.5 2.5 5.5 5.5 0 1-.3 1.9-.7 2.8l5.7 5.7v2h-4v-2h-2v-2h-2l-1.2-1.2c-.4.1-.9.2-1.3.2-3 0-5.5-2.5-5.5-5.5s2.5-5.5 5.5-5.5zm-1.5 5c.8 0 1.5-.7 1.5-1.5s-.7-1.5-1.5-1.5-1.5.7-1.5 1.5.7 1.5 1.5 1.5z" id="path336"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr.png
new file mode 100644
index 00000000..7af24724
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr.svg
new file mode 100644
index 00000000..ea5055c8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M3 7v9c0 1.7 1.3 3 3 3h15v-12h-18zm8 2h2v2h-2v-2zm0 3h2v2h-2v-2zm-3-3h2v2h-2v-2zm0 3h2v2h-2v-2zm-1 5h-1c-.6 0-1-.4-1-1v-1h2v2zm0-3h-2v-2h2v2zm0-3h-2v-2h2v2zm9 6h-8v-2h8v2zm0-3h-2v-2h2v2zm0-3h-2v-2h2v2zm3 6h-2v-2h2v2zm0-3h-2v-2h2v2zm0-3h-2v-2h2v2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl.png
new file mode 100644
index 00000000..b6e9b6ed
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl.svg
new file mode 100644
index 00000000..b35d108d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g346">
+ <path d="M21 7v9c0 1.7-1.3 3-3 3h-15v-12h18zm-8 2h-2v2h2v-2zm0 3h-2v2h2v-2zm3-3h-2v2h2v-2zm0 3h-2v2h2v-2zm1 5h1c.6 0 1-.4 1-1v-1h-2v2zm0-3h2v-2h-2v2zm0-3h2v-2h-2v2zm-9 6h8v-2h-8v2zm0-3h2v-2h-2v2zm0-3h2v-2h-2v2zm-3 6h2v-2h-2v2zm0-3h2v-2h-2v2zm0-3h2v-2h-2v2z" id="path348"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/language.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/language.png
new file mode 100644
index 00000000..c864384e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/language.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/language.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/language.svg
new file mode 100644
index 00000000..081e49a1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/language.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="language">
+ <path id="japanese" d="M17.533 9.81l.271-.59 1.041.407-.18.363c.661.271 1.101.468 1.312.589.331.211.618.514.86.905.211.393.316.846.316 1.358 0 .786-.302 1.479-.905 2.083-.604.634-1.66 1.057-3.169 1.268-.121-.361-.258-.679-.408-.95.965-.151 1.645-.333 2.037-.545.454-.21.785-.481.998-.813.21-.303.314-.663.314-1.087 0-.482-.136-.905-.407-1.269-.331-.331-.8-.589-1.402-.77-.333.634-.649 1.117-.951 1.449-.242.332-.694.906-1.358 1.721.09.393.181.709.272.951l-1.042.362-.091-.498c-.423.361-.801.617-1.133.77-.361.15-.664.226-.905.226-.303 0-.574-.136-.814-.407-.243-.301-.362-.68-.362-1.132 0-.604.136-1.147.407-1.63.241-.453.603-.89 1.086-1.313.272-.241.725-.528 1.359-.86 0-.271.03-.799.09-1.585-.514.03-.921.045-1.222.045-.393 0-.711-.015-.951-.045l-.046-1.041c.725.091 1.494.135 2.31.135 0-.149.075-.738.227-1.766l1.177.183c-.151.542-.256 1.041-.316 1.493.242-.029.543-.075.906-.136.362-.061.573-.091.634-.091s.648-.15 1.766-.453l.046 1.041c-.967.243-2.145.439-3.532.591-.062.663-.092 1.086-.092 1.266.663-.151 1.284-.225 1.857-.225zm-2.672 3.893c-.061-.481-.136-1.252-.227-2.31-.573.424-1.041.86-1.403 1.313-.303.423-.452.875-.452 1.358 0 .241.044.438.136.588.09.092.195.137.316.137.363.001.907-.361 1.63-1.086zm.771-2.763c0 .483.029 1.088.09 1.811.604-.905 1.057-1.599 1.359-2.082-.574.06-1.058.151-1.449.271z"/>
+ <path id="english" d="M9.497 15.981h1.851l-3.084-8.949h-1.85l-3.081 8.949h1.85l.557-1.981h3.209l.548 1.981zm-3.489-3.377l1.331-3.782 1.344 3.782h-2.675z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.png
new file mode 100644
index 00000000..dac7b2cc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.svg
new file mode 100644
index 00000000..47e71b39
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="layout-ltr">
+ <path id="text" d="M5 19v-14h6v8h8v6h-14z"/>
+ <path id="float" d="M13 5v6h6v-6h-6zm5 5h-4v-4h4v4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.png
new file mode 100644
index 00000000..470b7855
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.svg
new file mode 100644
index 00000000..fe9ee617
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="layout-rtl">
+ <path id="text" d="M5 19v-6h8v-8h6v14h-14z"/>
+ <path id="float" d="M5 5v6h6v-6h-6zm1 1h4v4h-4v-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr-invert.png
new file mode 100644
index 00000000..1b1e2ed3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr-invert.svg
new file mode 100644
index 00000000..c98df5cf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr-invert.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve"><style>* { fill: #FFFFFF }</style>
+<g>
+ <path d="M-471.2,493.6c-2.1,0-3.6,1.9-5.1,3.3c0.2,0,0.5-0.1,0.8-0.1c0.5,0,1,0.1,1.5,0.3c0.8-0.8,1.6-1.7,2.8-1.7
+ c0.6,0,1.3,0.3,1.8,0.7c1,1,1,2.6,0,3.6l-2.6,2.6c-0.4,0.4-1.2,0.7-1.8,0.7c-1.4,0-2.1-0.9-2.6-2l-1.3,1.3c0.8,1.5,2,2.6,3.8,2.6
+ c1.2,0,2.3-0.5,3-1.3l2.6-2.6c0.9-0.9,1.5-2,1.5-3.3C-467,495.5-469,493.6-471.2,493.6z M-475.5,505.7l-0.9,0.9
+ c-0.4,0.4-1.2,0.7-1.8,0.7c-0.6,0-1.3-0.3-1.8-0.7c-1-1-1-2.7,0-3.6l2.6-2.6c0.4-0.4,1.2-0.7,1.8-0.7c1.4,0,2.1,1,2.6,2l1.3-1.3
+ c-0.8-1.5-2-2.6-3.8-2.6c-1.2,0-2.3,0.5-3,1.3l-2.6,2.6c-1.7,1.7-1.7,4.4,0,6c1.6,1.6,4.4,1.7,5.9,0l1.9-1.9
+ c-0.3,0.1-0.6,0.1-0.9,0.1C-474.7,505.9-475.1,505.9-475.5,505.7z"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.png
new file mode 100644
index 00000000..1fe66f1e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.svg
new file mode 100644
index 00000000..841ba7d4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
+<g>
+ <path d="M-471.2,493.6c-2.1,0-3.6,1.9-5.1,3.3c0.2,0,0.5-0.1,0.8-0.1c0.5,0,1,0.1,1.5,0.3c0.8-0.8,1.6-1.7,2.8-1.7
+ c0.6,0,1.3,0.3,1.8,0.7c1,1,1,2.6,0,3.6l-2.6,2.6c-0.4,0.4-1.2,0.7-1.8,0.7c-1.4,0-2.1-0.9-2.6-2l-1.3,1.3c0.8,1.5,2,2.6,3.8,2.6
+ c1.2,0,2.3-0.5,3-1.3l2.6-2.6c0.9-0.9,1.5-2,1.5-3.3C-467,495.5-469,493.6-471.2,493.6z M-475.5,505.7l-0.9,0.9
+ c-0.4,0.4-1.2,0.7-1.8,0.7c-0.6,0-1.3-0.3-1.8-0.7c-1-1-1-2.7,0-3.6l2.6-2.6c0.4-0.4,1.2-0.7,1.8-0.7c1.4,0,2.1,1,2.6,2l1.3-1.3
+ c-0.8-1.5-2-2.6-3.8-2.6c-1.2,0-2.3,0.5-3,1.3l-2.6,2.6c-1.7,1.7-1.7,4.4,0,6c1.6,1.6,4.4,1.7,5.9,0l1.9-1.9
+ c-0.3,0.1-0.6,0.1-0.9,0.1C-474.7,505.9-475.1,505.9-475.5,505.7z"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl-invert.png
new file mode 100644
index 00000000..ead64bcc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl-invert.svg
new file mode 100644
index 00000000..91687845
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g358">
+ <path d="M9.025 3.6c2.1 0 3.6 1.9 5.1 3.3-.2 0-.5-.1-.8-.1-.5 0-1 .1-1.5.3-.8-.8-1.6-1.7-2.8-1.7-.6 0-1.3.3-1.8.7-1 1-1 2.6 0 3.6l2.6 2.6c.4.4 1.2.7 1.8.7 1.4 0 2.1-.9 2.6-2l1.3 1.3c-.8 1.5-2 2.6-3.8 2.6-1.2 0-2.3-.5-3-1.3l-2.6-2.6c-.9-.9-1.5-2-1.5-3.3.2-2.2 2.2-4.1 4.4-4.1zm4.3 12.1l.9.9c.4.4 1.2.7 1.8.7.6 0 1.3-.3 1.8-.7 1-1 1-2.7 0-3.6l-2.6-2.6c-.4-.4-1.2-.7-1.8-.7-1.4 0-2.1 1-2.6 2l-1.3-1.3c.8-1.5 2-2.6 3.8-2.6 1.2 0 2.3.5 3 1.3l2.6 2.6c1.7 1.7 1.7 4.4 0 6-1.6 1.6-4.4 1.7-5.9 0l-1.9-1.9c.3.1.6.1.9.1.5 0 .9 0 1.3-.2z" id="path360"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl.png
new file mode 100644
index 00000000..024c2dbf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl.svg
new file mode 100644
index 00000000..d4c2fd66
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g358">
+ <path d="M9.025 3.6c2.1 0 3.6 1.9 5.1 3.3-.2 0-.5-.1-.8-.1-.5 0-1 .1-1.5.3-.8-.8-1.6-1.7-2.8-1.7-.6 0-1.3.3-1.8.7-1 1-1 2.6 0 3.6l2.6 2.6c.4.4 1.2.7 1.8.7 1.4 0 2.1-.9 2.6-2l1.3 1.3c-.8 1.5-2 2.6-3.8 2.6-1.2 0-2.3-.5-3-1.3l-2.6-2.6c-.9-.9-1.5-2-1.5-3.3.2-2.2 2.2-4.1 4.4-4.1zm4.3 12.1l.9.9c.4.4 1.2.7 1.8.7.6 0 1.3-.3 1.8-.7 1-1 1-2.7 0-3.6l-2.6-2.6c-.4-.4-1.2-.7-1.8-.7-1.4 0-2.1 1-2.6 2l-1.3-1.3c.8-1.5 2-2.6 3.8-2.6 1.2 0 2.3.5 3 1.3l2.6 2.6c1.7 1.7 1.7 4.4 0 6-1.6 1.6-4.4 1.7-5.9 0l-1.9-1.9c.3.1.6.1.9.1.5 0 .9 0 1.3-.2z" id="path360"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.png
new file mode 100644
index 00000000..c73e1a14
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.svg
new file mode 100644
index 00000000..09a4ff5d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M21 7h-12v-2h12v2zm-14-1c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm14 7h-12v-2h12v2zm-14-1c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm14 7h-12v-2h12v2zm-14-1c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.png
new file mode 100644
index 00000000..e586f02e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.svg
new file mode 100644
index 00000000..67b9dfee
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M3 7h12v-2h-12v2zm14-1c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2zm-14 7h12v-2h-12v2zm14-1c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2zm-14 7h12v-2h-12v2zm14-1c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2z" id="path370"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.png
new file mode 100644
index 00000000..ab6dfe0d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.svg
new file mode 100644
index 00000000..87e8854e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M21 7h-13v-2h13v2zm0 6h-13v-2h13v2zm0 6h-13v-2h13v2zm-17-15h2v4h-1v-3h-1zm-1 6v-1h3v3h-2v1h2v1h-3v-3h2v-1zm3 10h-3v-1h2v-1h-1v-1h1v-1h-2v-1h3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.png
new file mode 100644
index 00000000..b433b2c8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.svg
new file mode 100644
index 00000000..831a5fb9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M3 7h13v-2h-13zm0 6h13v-2h-13zm0 6h13v-2h-13zm15-15h2v4h-1v-3h-1zm0 6v-1h3v3h-2v1h2v1h-3v-3h2v-1zm3 10h-3v-1h2v-1h-1v-1h1v-1h-2v-1h3z" id="path380"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-destructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-destructive.png
new file mode 100644
index 00000000..16974b22
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-destructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-destructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-destructive.svg
new file mode 100644
index 00000000..934cb4e5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-destructive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #D11D13 }</style>
+ <g id="g390">
+ <path d="M15 8s0-3-2.5-3-2.5 3-2.5 3v1h5zm2 0v1h2v10h-10c-1.7 0-3-1.3-3-3v-7h2v-1s0-5 4.5-5 4.5 5 4.5 5z" id="path392"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-invert.png
new file mode 100644
index 00000000..082f2e94
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-invert.svg
new file mode 100644
index 00000000..7aed0f67
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g390">
+ <path d="M15 8s0-3-2.5-3-2.5 3-2.5 3v1h5zm2 0v1h2v10h-10c-1.7 0-3-1.3-3-3v-7h2v-1s0-5 4.5-5 4.5 5 4.5 5z" id="path392"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr.png
new file mode 100644
index 00000000..06a6afb5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr.svg
new file mode 100644
index 00000000..59454922
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g390">
+ <path d="M15 8s0-3-2.5-3-2.5 3-2.5 3v1h5zm2 0v1h2v10h-10c-1.7 0-3-1.3-3-3v-7h2v-1s0-5 4.5-5 4.5 5 4.5 5z" id="path392"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-destructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-destructive.png
new file mode 100644
index 00000000..4bafac84
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-destructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-destructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-destructive.svg
new file mode 100644
index 00000000..64c23244
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-destructive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #D11D13 }</style>
+ <g id="g390">
+ <path d="M10 8s0-3 2.5-3 2.5 3 2.5 3v1h-5zm-2 0v1h-2v10h10c1.7 0 3-1.3 3-3v-7h-2v-1s0-5-4.5-5-4.5 5-4.5 5z" id="path392"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-invert.png
new file mode 100644
index 00000000..c5d842a5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-invert.svg
new file mode 100644
index 00000000..63cb2ebb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g390">
+ <path d="M10 8s0-3 2.5-3 2.5 3 2.5 3v1h-5zm-2 0v1h-2v10h10c1.7 0 3-1.3 3-3v-7h-2v-1s0-5-4.5-5-4.5 5-4.5 5z" id="path392"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl.png
new file mode 100644
index 00000000..15dd61e2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl.svg
new file mode 100644
index 00000000..0591f661
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g390">
+ <path d="M10 8s0-3 2.5-3 2.5 3 2.5 3v1h-5zm-2 0v1h-2v10h10c1.7 0 3-1.3 3-3v-7h-2v-1s0-5-4.5-5-4.5 5-4.5 5z" id="path392"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr.png
new file mode 100644
index 00000000..a08b6295
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr.svg
new file mode 100644
index 00000000..4af765ca
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M15 14v3l5-4.5-5-4.5v3h-7c0 1.7 1.3 3 3 3h4zm-1-9h-10v15h10v-2h-8v-11h8v-2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl.png
new file mode 100644
index 00000000..135df451
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl.svg
new file mode 100644
index 00000000..f72c04ad
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g402">
+ <path d="M9 14v3l-5-4.5 5-4.5v3h7c0 1.7-1.3 3-3 3h-4zm1-9h10v15h-10v-2h8v-11h-8v-2z" id="path404"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc.png
new file mode 100644
index 00000000..7c2c123a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc.svg
new file mode 100644
index 00000000..124b2101
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M12 6c-3.9 0-7 3.1-7 7s3.1 7 7 7 7-3.1 7-7-3.1-7-7-7zm0 13c-3.3 0-6-2.7-6-6s2.7-6 6-6 6 2.7 6 6-2.7 6-6 6zm-1.7-4.6c-.7 0-1-.4-1-1.2s.3-1.2 1-1.2c.4 0 .6.2.8.6l.9-.5c-.4-.7-1-1-1.9-1-.6 0-1.1.2-1.5.6s-.6.8-.6 1.5.2 1.2.6 1.6c.4.4.9.6 1.5.6.8 0 1.4-.4 1.9-1.1l-.9-.4c-.2.3-.5.5-.8.5zm4 0c-.7 0-1-.4-1-1.2s.3-1.2 1-1.2c.4 0 .6.2.8.6l.9-.5c-.4-.7-1-1-1.9-1-.6 0-1.1.2-1.5.6s-.6.8-.6 1.5.2 1.2.6 1.6c.4.4.9.6 1.5.6.8 0 1.4-.4 1.9-1.1l-.9-.4c-.2.3-.5.5-.8.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.png
new file mode 100644
index 00000000..df8600bd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.svg
new file mode 100644
index 00000000..079e1773
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M15.4 7.8c-2-.9-2.3-2.5-2.4-2.8.1.1 2 1 2 1l-3-5-3 5 2-1s0 .8.6 2.1c.8 1.5 2.2 2.2 2.2 2.2s1.6.7 2.2 1.3l-.7.7-.5-.5-.4 1.8 1.8-.4-.5-.5.7-.7c.9 1 1.5 2.3 1.6 3.8h-1v-.8l-1.5 1 1.5 1v-.8h1c-.1 1.5-.6 2.8-1.6 3.8l-.7-.7.5-.5-1.8-.4.4 1.8.5-.5.7.7c-1 .9-2.3 1.5-3.8 1.6v-1h.8l-1-1.5-1 1.5h.8v1c-1.5-.1-2.8-.6-3.8-1.6l.7-.7.5.5.4-1.8-1.8.4.5.5-.7.7c-.9-1-1.5-2.3-1.6-3.8h1v.8l1.5-1-1.5-1v.8h-1c.1-1.5.6-2.8 1.6-3.8l.7.7-.5.5 1.8.4-.4-1.8-.5.5-.7-.7-1.5-1.4c-1.5 1.4-2.5 3.5-2.5 5.8 0 4.4 3.6 8 8 8s8-3.6 8-8c0-3.2-1.9-5.9-4.6-7.2z"/>
+ <circle cx="12" cy="15" r="3"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.png
new file mode 100644
index 00000000..8629f29e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.svg
new file mode 100644
index 00000000..6672d9dc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M22.3 6.3c0 .2 0 .3-.1.3-.7.1-1.2.5-1.6 1.1-.1.2-.2.4-.3.7l-4.6 10.1c-.1.2-.2.3-.2.3s-.1.1-.2.1c-.2 0-.4-.1-.5-.4l-2.6-5.5-2.8 5.5c-.1.3-.3.4-.5.4s-.4-.1-.5-.4l-4.3-10.1c-.3-.8-.6-1.2-.8-1.4-.2-.2-.5-.3-1-.4-.1-.1-.1-.2-.1-.3 0-.2 0-.3.1-.3h4.3c.1.1.1.2.1.3 0 .2 0 .3-.1.3-.6.1-1 .2-1.1.4-.1.2 0 .6.3 1.2l3.6 8.2h.1l2.2-4.4-1.7-3.6c-.3-.7-.6-1.2-.8-1.4s-.5-.3-.9-.4c-.1-.1-.1-.2-.1-.3 0-.2 0-.3.1-.3h3.6c.1.1.1.2.1.3 0 .2 0 .3-.1.3-.4.1-.6.2-.6.4s.1.6.4 1.2l1 1.9 1-1.9c.3-.6.5-.9.5-1.1 0-.2 0-.3-.1-.4-.1-.1-.3-.1-.5-.1l-.1-.3c0-.2 0-.3.1-.3h3c.1.1.1.2.1.3 0 .2 0 .3-.1.3-.5.1-.8.2-1.1.5-.3.3-.6.7-.8 1.3l-1.3 2.8 2.5 5.2h.1l3.7-8.1c.3-.5.3-.9.2-1.2-.1-.3-.5-.4-1.1-.5-.1-.1-.1-.2-.1-.3s0-.3.1-.3h3.7c-.2.1-.2.2-.2.3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.png
new file mode 100644
index 00000000..3629f55f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.svg
new file mode 100644
index 00000000..0fc47737
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M15 6l-6-2-6 2v15l6-2 6 2 6-2v-15l-6 2zm-6.3 12.1l-4.7 1.5v-12.9l5-1.7v12.9l-.3.2zm11.3.2l-5 1.7v-12.9l.3-.1 4.7-1.6v12.9z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.png
new file mode 100644
index 00000000..5d1362fc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.svg
new file mode 100644
index 00000000..b33f1e39
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M9 6l6-2 6 2v15l-6-2-6 2-6-2v-15l6 2zm6.3 12.1l4.7 1.5v-12.9l-5-1.7v12.9l.3.2zm-11.3.2l5 1.7v-12.9l-.3-.1-4.7-1.6v12.9z" id="path424"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.png
new file mode 100644
index 00000000..46b31a4e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.svg
new file mode 100644
index 00000000..f422c84f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M19 12c0-3.9-3.1-7-7-7s-7 3.1-7 7c0 1.4.4 2.6 1.1 3.7l5.9 7.3 5.9-7.3c.7-1.1 1.1-2.3 1.1-3.7zm-7 4c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z" id="path4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.png
new file mode 100644
index 00000000..6d51b9ac
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.svg
new file mode 100644
index 00000000..9a54eb6a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g434">
+ <g id="g436">
+ <path d="M24 4h-4v-4h-2v4h-4v2h4v4h2v-4h4z" id="path438"/>
+ </g>
+ </g>
+ <path d="M18 11h-1v-3.9l-.1-.1h-3.9v-1.9c-.3-.1-.7-.1-1-.1-3.9 0-7 3.1-7 7 0 1.4.4 2.6 1.1 3.7l5.9 7.3 5.9-7.3c.7-1.1 1.1-2.3 1.1-3.7 0-.3 0-.7-.1-1h-.9zm-6 5c-2.2 0-4-1.8-4-4s1.8-4 4-4 4 1.8 4 4-1.8 4-4 4z" id="path440"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.png
new file mode 100644
index 00000000..b7797c40
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.svg
new file mode 100644
index 00000000..d3e152e0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g434">
+ <g id="g436">
+ <path d="M0 4h4v-4h2v4h4v2h-4v4h-2v-4h-4z" id="path438"/>
+ </g>
+ </g>
+ <path d="M6 11h1v-3.9l.1-.1h3.9v-1.9c.3-.1.7-.1 1-.1 3.9 0 7 3.1 7 7 0 1.4-.4 2.6-1.1 3.7l-5.9 7.3-5.9-7.3c-.7-1.1-1.1-2.3-1.1-3.7 0-.3 0-.7.1-1h.9zm6 5c2.2 0 4-1.8 4-4s-1.8-4-4-4-4 1.8-4 4 1.8 4 4 4z" id="path440"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.png
new file mode 100644
index 00000000..0246e4d3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.svg
new file mode 100644
index 00000000..61b8877f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve"><style>* { fill: #FFFFFF }</style>
+<g id="menu">
+ <path id="lines" d="M-481,505h12c0.6,0,1,0.4,1,1v1c0,0.6-0.4,1-1,1h-12c-0.6,0-1-0.4-1-1v-1C-482,505.4-481.6,505-481,505z
+ M-482,501v1c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1v-1c0-0.6-0.4-1-1-1h-12C-481.6,500-482,500.4-482,501z M-482,496v1
+ c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1v-1c0-0.6-0.4-1-1-1h-12C-481.6,495-482,495.4-482,496z"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.png
new file mode 100644
index 00000000..de7b1d24
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.svg
new file mode 100644
index 00000000..89fd9789
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
+<g id="menu">
+ <path id="lines" d="M-481,505h12c0.6,0,1,0.4,1,1v1c0,0.6-0.4,1-1,1h-12c-0.6,0-1-0.4-1-1v-1C-482,505.4-481.6,505-481,505z
+ M-482,501v1c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1v-1c0-0.6-0.4-1-1-1h-12C-481.6,500-482,500.4-482,501z M-482,496v1
+ c0,0.6,0.4,1,1,1h12c0.6,0,1-0.4,1-1v-1c0-0.6-0.4-1-1-1h-12C-481.6,495-482,495.4-482,496z"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.png
new file mode 100644
index 00000000..279c61d1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.svg
new file mode 100644
index 00000000..3f308ff7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M21 9c0-1.7-1.3-3-3-3h-15v3l9 4 9-4zm-18 2v6c0 1.7 1.3 3 3 3h15v-9l-9 4-9-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl.png
new file mode 100644
index 00000000..c44dea05
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl.svg
new file mode 100644
index 00000000..fa61aa18
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g450">
+ <path d="M3 9c0-1.7 1.3-3 3-3h15v3l-9 4-9-4zm18 2v6c0 1.7-1.3 3-3 3h-15v-9l9 4 9-4z" id="path452"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr-invert.png
new file mode 100644
index 00000000..7c9bdc1c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr-invert.svg
new file mode 100644
index 00000000..10f0c4e5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="move-ltr">
+ <path id="arrow" d="M8.935 7.181l5.302 5.302-5.302 5.303 1.414 1.414 6.716-6.717-6.716-6.716z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr.png
new file mode 100644
index 00000000..fc4cd390
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/move-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr.svg
index eea75d8f..51e6611a 100644
--- a/resources/lib/oojs-ui/images/icons/move-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="move-ltr" opacity=".75">
+ <g id="move-ltr">
<path id="arrow" d="M8.935 7.181l5.302 5.302-5.302 5.303 1.414 1.414 6.716-6.717-6.716-6.716z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl-invert.png
new file mode 100644
index 00000000..e97d37b9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl-invert.svg
new file mode 100644
index 00000000..002ec0f6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="move-rtl">
+ <path id="arrow" d="M15.065 17.786l-5.302-5.303 5.302-5.302-1.414-1.414-6.716 6.716 6.716 6.717z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.png
new file mode 100644
index 00000000..dbce05ec
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/move-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.svg
index 2dc5eaf6..bcee09d9 100644
--- a/resources/lib/oojs-ui/images/icons/move-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="move-rtl" opacity=".75">
+ <g id="move-rtl">
<path id="arrow" d="M15.065 17.786l-5.302-5.303 5.302-5.302-1.414-1.414-6.716 6.716 6.716 6.717z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move.png
new file mode 100644
index 00000000..7ba0ee93
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move.svg
new file mode 100644
index 00000000..9063bd48
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M20 11l-4-3v2h-3v-3h2l-3-4-3 4h2v3h-3v-2l-4 3 4 3v-2h3v3h-2l3 4 3-4h-2v-3h3v2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.png
new file mode 100644
index 00000000..ed7b930f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.svg
new file mode 100644
index 00000000..b8ea833e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g4">
+ <path d="M12 5l2.5 2.5-3.5 3.5c-1.2 1.2-1.2 2.8 0 4l5.5-5.5 2.5 2.5v-7h-7zm5 12h-9c-.6 0-1-.4-1-1v-9h3l-2-2h-3v11c0 1.7 1.3 3 3 3h11v-3l-2-2v3z" id="path6"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl.png
new file mode 100644
index 00000000..46567c77
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl.svg
new file mode 100644
index 00000000..58a9eeb2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g462">
+ <path d="M12 5l-2.5 2.5 3.5 3.5c1.2 1.2 1.2 2.8 0 4l-5.5-5.5-2.5 2.5v-7h7zm-5 12h9c.6 0 1-.4 1-1v-9h-3l2-2h3v11c0 1.7-1.3 3-3 3h-11v-3l2-2v3z" id="path464"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.png
new file mode 100644
index 00000000..d4b638a2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.svg
new file mode 100644
index 00000000..dad5f51c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="line_return">
+ <path d="M17.8 5.7c-.5 0-.9.2-1.2.5s-.5.7-.5 1.2v4.3h-5.1v-4l-6 5.5 6 5.5v-4h8v-9h-1.2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl.png
new file mode 100644
index 00000000..20f5d0db
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl.svg
new file mode 100644
index 00000000..fd758cc6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="line_return">
+ <path d="M6.2 5.7c.5 0 .9.2 1.2.5.3.3.5.7.5 1.2v4.3H13v-4l6 5.5-6 5.5v-4H5v-9h1.2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.png
new file mode 100644
index 00000000..056e7dd8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.svg
new file mode 100644
index 00000000..46471a33
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M6 7v12c-.6 0-1-.4-1-1v-9h-1v9c0 1.1.9 2 2 2h15v-13h-15zm9 11h-7v-1h7v1zm0-2h-7v-1h7v1zm0-2h-7v-1h7v1zm4 4h-3v-5h3v5zm0-7h-11v-2h11v2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.png
new file mode 100644
index 00000000..8221a093
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.svg
new file mode 100644
index 00000000..7564dff0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M19 7v12c.6 0 1-.4 1-1v-9h1v9c0 1.1-.9 2-2 2h-15v-13h15zm-9 11h7v-1h-7v1zm0-2h7v-1h-7v1zm0-2h7v-1h-7v1zm-4 4h3v-5h-3v5zm0-7h11v-2h-11v2z" id="path474"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr.png
new file mode 100644
index 00000000..8b15525d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr.svg
new file mode 100644
index 00000000..601428e2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M16 14l2 2v-11h-4v2h2zm0 2l-7-7-2-2-1-1-1-1-3-3-1 1 2 2h-1v14h4v-2h-2v-10h1l2 2v10h4v-2h-2v-6l6 6h-1v2h3l4 4 1-1-4-4zm-5-9v-2h-4l2 2zm8-2v2h2v10h-2l2 2h2v-14z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl.png
new file mode 100644
index 00000000..f7bab384
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl.svg
new file mode 100644
index 00000000..31785a3c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g484">
+ <path d="M8 14l-2 2v-11h4v2h-2zm0 2l7-7 2-2 1-1 1-1 3-3 1 1-2 2h1v14h-4v-2h2v-10h-1l-2 2v10h-4v-2h2v-6l-6 6h1v2h-3l-4 4-1-1 4-4zm5-9v-2h4l-2 2zm-8-2v2h-2v10h2l-2 2h-2v-14z" id="path486"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr.png
new file mode 100644
index 00000000..4ac336c4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr.svg
new file mode 100644
index 00000000..4264ff08
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M10 8h9v2h-9v-2zm0 3h9v2h-9v-2zm0 3h6v2h-6v-2zm11-8h-18v-2h18v2zm0 14h-18v-2h18v2zm-18-8l5 4v-8l-5 4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl.png
new file mode 100644
index 00000000..68577dd0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl.svg
new file mode 100644
index 00000000..2479343e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g496">
+ <path d="M14 8h-9v2h9v-2zm0 3h-9v2h9v-2zm0 3h-6v2h6v-2zm-11-8h18v-2h-18v2zm0 14h18v-2h-18v2zm18-8l-5 4v-8l5 4z" id="path498"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.png
new file mode 100644
index 00000000..a9a186b0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.svg
new file mode 100644
index 00000000..9c0ea598
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="outline-ltr">
+ <path id="text" d="M5 13h14v6h-14v-6z"/>
+ <path id="float" d="M5 5v6h6v-6h-6zm5 5h-4v-4h4v4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.png
new file mode 100644
index 00000000..b7f025d8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.svg
new file mode 100644
index 00000000..2a3428e9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="outline-rtl">
+ <path id="text" d="M19 19h-14v-6h14v6z"/>
+ <path id="float" d="M13 5v6h6v-6h-6zm1 1h4v4h-4v-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr.png
new file mode 100644
index 00000000..38a90e22
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr.svg
new file mode 100644
index 00000000..92fc07ed
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M2 3h18v2h-16v12h-2v-14zm13 13l-4-4-4 5h13l-3-3-2 2zm-10-10h17v13h-17v-13z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl.png
new file mode 100644
index 00000000..bcb805d2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl.svg
new file mode 100644
index 00000000..d989d3d4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g508">
+ <path d="M22 3h-18v2h16v12h2v-14zm-13 13l4-4 4 5h-13l3-3 2 2zm10-10h-17v13h17v-13z" id="path510"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.png
new file mode 100644
index 00000000..d6dc62c4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.svg
new file mode 100644
index 00000000..55e0b7f1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="picture">
+ <path id="frame" d="M18 4h-12c-2-.007-3 .993-3 2.993l.014 9.007c-.014 2 .986 2.988 2.986 3h12c2-.012 2.994-1 3-3.006v-9.001c-.006-2-1-3-3-2.993zm1 13h-14v-11h14v11z"/>
+ <path id="mountains" d="M6 13.5l3.5-3.5 2.328 2.312-1.312 1.094.875 1.032 4.109-3.438 2.5 2v3h-12z"/>
+ <path id="sky" d="M6 12l3.516-4.156 3.046 3.172 2.938-2.016 2.5 2v-4h-12z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.png
new file mode 100644
index 00000000..20434248
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/picture.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.svg
index 4862fbc5..7400bca9 100644
--- a/resources/lib/oojs-ui/images/icons/picture.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="picture" opacity=".75">
+ <g id="picture">
<path id="frame" d="M18 4h-12c-2-.007-3 .993-3 2.993l.014 9.007c-.014 2 .986 2.988 2.986 3h12c2-.012 2.994-1 3-3.006v-9.001c-.006-2-1-3-3-2.993zm1 13h-14v-11h14v11z"/>
<path id="mountains" d="M6 13.5l3.5-3.5 2.328 2.312-1.312 1.094.875 1.032 4.109-3.438 2.5 2v3h-12z"/>
<path id="sky" d="M6 12l3.516-4.156 3.046 3.172 2.938-2.016 2.5 2v-4h-12z"/>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr.png
new file mode 100644
index 00000000..c5050e0b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr.svg
new file mode 100644
index 00000000..5ce95636
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M12 5c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm-2 12v-8l6 4-6 4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl.png
new file mode 100644
index 00000000..1264e9f4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl.svg
new file mode 100644
index 00000000..591a5d3a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g520">
+ <path d="M12 5c4.4 0 8 3.6 8 8s-3.6 8-8 8-8-3.6-8-8 3.6-8 8-8zm2 12v-8l-6 4 6 4z" id="path522"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.png
new file mode 100644
index 00000000..051ab1d2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.svg
new file mode 100644
index 00000000..baae35e9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M18 8h-1v-4h-10v4h-4v6c0 1.7 1.3 3 3 3h1v3h10v-3h4v-6c0-1.7-1.3-3-3-3zm-10-3h8v3h-8v-3zm8 14h-8v-6h8v6z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.png
new file mode 100644
index 00000000..18e247d4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.svg
new file mode 100644
index 00000000..8294afd5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M6 8h1v-4h10v4h4v6c0 1.7-1.3 3-3 3h-1v3h-10v-3h-4v-6c0-1.7 1.3-3 3-3zm10-3h-8v3h8v-3zm-8 14h8v-6h-8v6z" id="path532"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.png
new file mode 100644
index 00000000..f6a9c860
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.svg
new file mode 100644
index 00000000..97b77bb4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M18 9.9c-.7 0-1.4.3-1.8.9v-4.8h-4c.2-.4.4-.8.4-1.2 0-1.2-1-2.2-2.2-2.2-1.3-.1-2.3.9-2.3 2.2 0 .4.2.8.4 1.2h-4.4v3.6l.6-.1c1.4 0 2.5 1.1 2.5 2.5s-1.1 2.5-2.5 2.5c-.2 0-.4 0-.6-.1v3.6h4.9c-.5.4-.9 1-.9 1.8 0 1.2 1 2.2 2.3 2.2 1.2 0 2.2-1 2.2-2.2 0-.7-.3-1.4-.9-1.8h4.5v-4.5c.4.5 1 .9 1.8.9 1.2 0 2.2-1 2.2-2.2 0-1.3-1-2.3-2.2-2.3z" id="path542"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.png
new file mode 100644
index 00000000..03050e1c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.svg
new file mode 100644
index 00000000..0ad5f375
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M6.3 9.9c.7 0 1.4.3 1.8.9v-4.8h4c-.2-.4-.4-.8-.4-1.2 0-1.2 1-2.2 2.2-2.2 1.3-.1 2.3.9 2.3 2.2 0 .4-.2.8-.4 1.2h4.4v3.6l-.6-.1c-1.4 0-2.5 1.1-2.5 2.5s1.1 2.5 2.5 2.5c.2 0 .4 0 .6-.1v3.6h-4.9c.5.4.9 1 .9 1.8 0 1.2-1 2.2-2.3 2.2-1.2 0-2.2-1-2.2-2.2 0-.7.3-1.4.9-1.8h-4.5v-4.5c-.4.5-1 .9-1.8.9-1.2 0-2.2-1-2.2-2.2 0-1.3 1-2.3 2.2-2.3z" id="path542"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.png
new file mode 100644
index 00000000..ffe3601d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.svg
new file mode 100644
index 00000000..b3b923e5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
+<g>
+ <path d="M-468.9,498.1c0.2-0.1,0.5-0.2,0.6-0.5s0.2-0.5,0.2-0.9V496c-1,0.2-1.5,0.2-2.6,0.6c-0.7,0.4-1.2,0.9-1.7,1.4
+ c-0.5,0.5-1.9,2.6-1.9,5.8v3.1h4.7c0.9,0,1.6-0.7,1.6-1.6v-4.7h-3.1c0,0,0.1-0.7,0.6-1.4C-470,498.7-469.5,498.3-468.9,498.1z
+ M-480.1,498c-0.5,0.5-1.9,2.9-1.9,6v2.9h4.7c0.9,0,1.6-0.7,1.6-1.6v-4.7h-3.1c0,0,0.1-0.7,0.6-1.4c0.5-0.5,1-0.9,1.6-1.2
+ c0.2-0.1,0.5-0.2,0.6-0.5s0.2-0.5,0.2-0.9V496c-1,0.2-1.5,0.2-2.6,0.6C-479,497-479.6,497.5-480.1,498z"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.png
new file mode 100644
index 00000000..a2acf5e9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.svg
new file mode 100644
index 00000000..b40a8ac9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-487 489 24 24" enable-background="new -487 489 24 24" xml:space="preserve">
+<g>
+ <path d="M-479.5,499.3c0.5,0.7,0.6,1.4,0.6,1.4h-3.1v4.7c0,0.9,0.7,1.6,1.6,1.6h4.7v-3.1c0-3.1-1.5-5.2-1.9-5.8
+ c-0.5-0.5-1-1-1.7-1.4c-1.1-0.5-1.6-0.5-2.6-0.6v0.8c0,0.3,0.1,0.6,0.2,0.9s0.4,0.4,0.6,0.5C-480.5,498.3-480,498.7-479.5,499.3z
+ M-471.7,496.6c-1.1-0.5-1.6-0.5-2.6-0.6v0.8c0,0.3,0.1,0.6,0.2,0.9s0.4,0.4,0.6,0.5c0.6,0.2,1.2,0.6,1.6,1.2
+ c0.5,0.7,0.6,1.4,0.6,1.4h-3.1v4.7c0,0.9,0.7,1.6,1.6,1.6h4.7V504c0-3.1-1.5-5.4-1.9-6C-470.4,497.5-471,497-471.7,496.6z"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.png
new file mode 100644
index 00000000..b04ec747
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.svg
new file mode 100644
index 00000000..24fca8f5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g4">
+ <path d="M3.5 8.6c-.6.7-2.5 3.4-2.5 7.4v4h6c1.1 0 2-.9 2-2v-6h-4s.1-.9.8-1.8c.6-.7 1.3-1.2 2.1-1.5.3-.1.6-.3.8-.6.2-.3.3-.7.3-1.1v-1c-1.3.2-1.9.2-3.3.8-.8.5-1.6 1.1-2.2 1.8zm15.5-3.6v-4h-2v4h-4v2h4v4h2v-4h4v-2zm-4 7s.1-.9.8-1.8l.2-.2v-2h-1.9l-.6.6c-.6.7-2.5 3.4-2.5 7.4v4h6c1.1 0 2-.9 2-2v-6h-4z" id="path6"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.png
new file mode 100644
index 00000000..9e912026
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.svg
new file mode 100644
index 00000000..736f2a6d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g4">
+ <path d="M20.5 8.6c.6.7 2.5 3.4 2.5 7.4v4h-6c-1.1 0-2-.9-2-2v-6h4s-.1-.9-.8-1.8c-.6-.7-1.3-1.2-2.1-1.5-.3-.1-.6-.3-.8-.6-.2-.3-.3-.7-.3-1.1v-1c1.3.2 1.9.2 3.3.8.8.5 1.6 1.1 2.2 1.8zm-15.5-3.6v-4h2v4h4v2h-4v4h-2v-4h-4v-2zm4 7s-.1-.9-.8-1.8l-.2-.2v-2h1.9l.6.6c.6.7 2.5 3.4 2.5 7.4v4h-6c-1.1 0-2-.9-2-2v-6h4z" id="path6"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.png
new file mode 100644
index 00000000..3bca20fe
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.svg
new file mode 100644
index 00000000..884d40df
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="create_redirect">
+ <g>
+ <path d="M17.7 2.4c-.3-.3-.7-.4-1.2-.4h-12.1v16.2c0 .5.1.8.4 1.1s.7.7 1.2.7h10.2c-.6-.2-1.2-.5-1.9-1-.4-.3-.8-.6-1.2-1l-.5-.6h-6.2v-1.4h5.4s-.4-1.5-.4-2h-5v-1h9v1c.4.1 1.1.1 1.5.1.4 0 .7 0 1.1-.1v-10.5c.1-.5-.1-.9-.3-1.1zm-5.2 1.6h3v4.5h-3v-4.5zm-6.1 0h4v1.6h-4v-1.6zm0 3h4v1.5h-4v-1.5zm0 3h9v1.5h-9v-1.5zm12.7 3.1l4.9 3.8-4.9 4.8v-2.2c-1.7 0-2.9-.2-4.3-1.2-1.2-.8-2.5-2.6-2.3-4.1 1.4 1 2.9 1.5 4.4 1.5.7 0 1.4-.1 2.1-.3l.1-2.3"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.png
new file mode 100644
index 00000000..dc9b0e63
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.svg
new file mode 100644
index 00000000..a07e8364
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="create_redirect">
+ <g id="g3264">
+ <path d="M6.3 2.4c.3-.3.7-.4 1.2-.4h12.1v16.2c0 .5-.1.8-.4 1.1-.3.3-.7.7-1.2.7h-10.2c.6-.2 1.2-.5 1.9-1 .4-.3.8-.6 1.2-1l.5-.6h6.2v-1.4h-5.4s.4-1.5.4-2h5v-1h-9v1c-.4.1-1.1.1-1.5.1-.4 0-.7 0-1.1-.1v-10.5c-.1-.5.1-.9.3-1.1zm5.2 1.6h-3v4.5h3v-4.5zm6.1 0h-4v1.6h4v-1.6zm0 3h-4v1.5h4v-1.5zm0 3h-9v1.5h9v-1.5z" id="path3266"/>
+ <path d="M4.9 13.1l-4.9 3.8 4.9 4.8v-2.2c1.7 0 2.9-.2 4.3-1.2 1.2-.8 2.5-2.6 2.3-4.1-1.4 1-2.9 1.5-4.4 1.5-.7 0-1.4-.1-2.1-.3l-.1-2.3" id="path3268"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.png
new file mode 100644
index 00000000..46439283
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.svg
new file mode 100644
index 00000000..7b672618
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="regular-expression">
+ <path id="left-bracket" d="m 3,12.044797 c -5e-7,-0.989171 0.150394,-1.914889 0.451184,-2.7771612 C 3.7558785,8.4053812 4.1933899,7.6495032 4.7637193,7 L 6.2286026,7 C 5.6778034,7.7204251 5.261777,8.511764 4.9805221,9.3740188 4.6992623,10.236291 4.5586337,11.122815 4.5586357,12.033598 c -2e-6,0.914522 0.1425798,1.799179 0.427746,2.653974 C 5.2754491,15.538635 5.6856161,16.309444 6.2168835,17 L 4.7637193,17 C 4.1894835,16.365435 3.7519721,15.624488 3.451184,14.777158 3.150394,13.929828 3,13.019042 3,12.044797" />
+ <path id="dot" d="m 10,16 c 0,0.552285 -0.4477153,1 -1,1 -0.5522847,0 -1,-0.447715 -1,-1 0,-0.552285 0.4477153,-1 1,-1 0.5522847,0 1,0.447715 1,1 z" />
+ <path id="star" d="m 14.250652,7.0127142 -0.240235,2.15625 2.185547,-0.609375 0.193359,1.4765618 -1.992187,0.140625 1.306641,1.740234 -1.330079,0.708985 -0.914062,-1.833985 -0.802734,1.822266 -1.382813,-0.697266 1.294922,-1.740234 -1.980469,-0.152343 0.228516,-1.4648438 2.138672,0.609375 -0.240235,-2.15625 1.535157,0" />
+ <path id="right-bracket" d="m 21,12.044797 c -3e-6,0.981711 -0.152351,1.896229 -0.457043,2.743558 C 20.241767,15.635686 19.806209,16.3729 19.235883,17 l -1.453164,0 c 0.527356,-0.686824 0.93557,-1.455766 1.224642,-2.306829 0.289069,-0.854795 0.433604,-1.741318 0.433606,-2.659573 -2e-6,-0.910783 -0.140631,-1.797307 -0.421886,-2.6595792 C 18.737821,8.511764 18.321795,7.7204251 17.771,7 l 1.464883,0 c 0.574232,0.653236 1.011744,1.4128466 1.312536,2.2788341 0.300785,0.8622719 0.45118,1.7842569 0.451183,2.7659629" />
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.png
new file mode 100644
index 00000000..84e64984
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.svg
new file mode 100644
index 00000000..3551e582
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #D11D13 }</style>
+ <g id="remove">
+ <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0h-1v6h1v-6zm4 0h-1v6h1v-6zm0-4v-1h-5v1h-3v3h1v7.966l1 1.031v-.074.077h6.984l.016-.018v.015l1-1.031v-7.966h1v-3h-3zm1 11h-7v-8h7v8zm1-9h-9v-1h9v1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.png
new file mode 100644
index 00000000..3343de8b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.svg
new file mode 100644
index 00000000..ddc352fe
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="remove">
+ <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0h-1v6h1v-6zm4 0h-1v6h1v-6zm0-4v-1h-5v1h-3v3h1v7.966l1 1.031v-.074.077h6.984l.016-.018v.015l1-1.031v-7.966h1v-3h-3zm1 11h-7v-8h7v8zm1-9h-9v-1h9v1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove.png
new file mode 100644
index 00000000..9dc34b8a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/remove.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove.svg
index 61f4d2da..6ad79174 100644
--- a/resources/lib/oojs-ui/images/icons/remove.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="remove" opacity=".75">
+ <g id="remove">
<path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0h-1v6h1v-6zm4 0h-1v6h1v-6zm0-4v-1h-5v1h-3v3h1v7.966l1 1.031v-.074.077h6.984l.016-.018v.015l1-1.031v-7.966h1v-3h-3zm1 11h-7v-8h7v8zm1-9h-9v-1h9v1z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.png
new file mode 100644
index 00000000..ebce3c0b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.svg
new file mode 100644
index 00000000..6e4979f8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="Layer_1">
+ <g>
+ <circle cx="11.5" cy="8.5" r="2.5"/>
+ <path d="M16.3 8.7l.7-.7-.8-.8.4-.8-1.1-.5.1-.9-1.2-.2-.1-.9-1.2.2-.4-.8-1.1.5-.6-.8-.8.8-.9-.4-.5 1.1-.9-.2-.2 1.2-.9.2.2 1.2-.9.4.5 1.1-.6.6.8.8-.4.8 1.1.5-.1.9 1.2.2.1.9 1.2-.2.4.8 1.1-.5.6.8.8-.8.8.4.5-1.1.9.1.2-1.2.9-.1-.2-1.2.8-.4-.4-1zm-4.8 3.3c-1.9 0-3.5-1.6-3.5-3.5s1.6-3.5 3.5-3.5 3.5 1.6 3.5 3.5-1.6 3.5-3.5 3.5zm.5 3l-.7-.7-1.1.6-.4-.7-.8.3v8.5l2.5-3 2.5 3v-8.5l-1-.5z"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr-invert.png
new file mode 100644
index 00000000..4b6ecd2f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr-invert.svg
new file mode 100644
index 00000000..3d587833
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="search">
+ <path id="magnifying-glass" d="M 10.5,4 C 6.9101491,4 4,6.9101491 4,10.5 c 0,3.589851 2.9101491,6.5 6.5,6.5 1.02211,0 1.983324,-0.235899 2.84375,-0.65625 L 16,19 c 1.4,1.4 2.5,1.5 4,0 L 15.5625,14.5625 C 16.462737,13.447115 17,12.044969 17,10.5 17,6.9101491 14.089851,4 10.5,4 z m 0,2 C 12.985281,6 15,8.0147186 15,10.5 15,12.985281 12.985281,15 10.5,15 8.0147186,15 6,12.985281 6,10.5 6,8.0147186 8.0147186,6 10.5,6 z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.png
new file mode 100644
index 00000000..c10dc664
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.svg
new file mode 100644
index 00000000..cdcbc30d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="search">
+ <path id="magnifying-glass" d="M 10.5,4 C 6.9101491,4 4,6.9101491 4,10.5 c 0,3.589851 2.9101491,6.5 6.5,6.5 1.02211,0 1.983324,-0.235899 2.84375,-0.65625 L 16,19 c 1.4,1.4 2.5,1.5 4,0 L 15.5625,14.5625 C 16.462737,13.447115 17,12.044969 17,10.5 17,6.9101491 14.089851,4 10.5,4 z m 0,2 C 12.985281,6 15,8.0147186 15,10.5 15,12.985281 12.985281,15 10.5,15 8.0147186,15 6,12.985281 6,10.5 6,8.0147186 8.0147186,6 10.5,6 z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl-invert.png
new file mode 100644
index 00000000..7868dc11
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl-invert.svg
new file mode 100644
index 00000000..91130f08
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="search">
+ <path id="magnifying-glass" d="m 13.5,4 c 3.589851,0 6.5,2.9101491 6.5,6.5 0,3.589851 -2.910149,6.5 -6.5,6.5 -1.02211,0 -1.983324,-0.235899 -2.84375,-0.65625 L 8,19 C 6.6,20.4 5.5,20.5 4,19 L 8.4375,14.5625 C 7.537263,13.447115 7,12.044969 7,10.5 7,6.9101491 9.910149,4 13.5,4 z m 0,2 C 11.014719,6 9,8.0147186 9,10.5 9,12.985281 11.014719,15 13.5,15 15.985281,15 18,12.985281 18,10.5 18,8.0147186 15.985281,6 13.5,6 z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.png
new file mode 100644
index 00000000..dab4ff14
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.svg
new file mode 100644
index 00000000..c6753493
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="search">
+ <path id="magnifying-glass" d="m 13.5,4 c 3.589851,0 6.5,2.9101491 6.5,6.5 0,3.589851 -2.910149,6.5 -6.5,6.5 -1.02211,0 -1.983324,-0.235899 -2.84375,-0.65625 L 8,19 C 6.6,20.4 5.5,20.5 4,19 L 8.4375,14.5625 C 7.537263,13.447115 7,12.044969 7,10.5 7,6.9101491 9.910149,4 13.5,4 z m 0,2 C 11.014719,6 9,8.0147186 9,10.5 9,12.985281 11.014719,15 13.5,15 15.985281,15 18,12.985281 18,10.5 18,8.0147186 15.985281,6 13.5,6 z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link-invert.png
new file mode 100644
index 00000000..0e9a5c57
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link-invert.svg
new file mode 100644
index 00000000..2aeba4ea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
+ <g id="secure">
+ <path id="lock" d="M8 5h.019v-.997c.001-.057.004-1.409-.832-2.255-.434-.438-.998-.66-1.679-.66s-1.245.222-1.678.659c-.837.847-.833 2.199-.832 2.251v1.002h.002c-.553 0-1 .447-1 1v3c0 .553.447 1 1 1h5c.553 0 1-.447 1-1v-3c0-.553-.447-1-1-1zm-4.002 0v-1.007c0-.01.005-.999.543-1.543.482-.485 1.449-.487 1.932-.002.544.546.546 1.536.546 1.55v1.002h-3.021z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.png
new file mode 100644
index 00000000..918b3d7b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.svg
new file mode 100644
index 00000000..a9c7d276
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+ <g id="secure">
+ <path id="lock" d="M8 5h.019v-.997c.001-.057.004-1.409-.832-2.255-.434-.438-.998-.66-1.679-.66s-1.245.222-1.678.659c-.837.847-.833 2.199-.832 2.251v1.002h.002c-.553 0-1 .447-1 1v3c0 .553.447 1 1 1h5c.553 0 1-.447 1-1v-3c0-.553-.447-1-1-1zm-4.002 0v-1.007c0-.01.005-.999.543-1.543.482-.485 1.449-.487 1.932-.002.544.546.546 1.536.546 1.55v1.002h-3.021z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.png
new file mode 100644
index 00000000..17b4379c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.svg
new file mode 100644
index 00000000..c6eba159
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="settings">
+ <path id="gear" d="M3 4h3v2h-3zM12 4h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 11h9v2h-9zM18 11h3v2h-3zM14 10h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2h-6zM15 18h6v2h-6zM11 17h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings.png
new file mode 100644
index 00000000..dd2706b4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/settings.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings.svg
index 6e45b60d..bcd665ee 100644
--- a/resources/lib/oojs-ui/images/icons/settings.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings.svg
@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0, 0, 24, 24">
- <g id="settings" opacity=".75">
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="settings">
<path id="gear" d="M3 4h3v2h-3zM12 4h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 11h9v2h-9zM18 11h3v2h-3zM14 10h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2h-6zM15 18h6v2h-6zM11 17h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.png
new file mode 100644
index 00000000..30e88db9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.svg
new file mode 100644
index 00000000..0d495049
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M0 20h24v1h-24v-1zm6-8l-1-1-2 2-2-2-1 1 2 2-2 2 1 1 2-2 2 2 1-1-2-2zm15.6 3.7c-.9-.5-1.9-.5-2.7 0-1.5.9-3.1.4-3.1.4-.4-.2-.8-.4-1.1-.6 2.2-.6 4.4-1.8 6-3.9 1.1-1.2 2.5-3.9.4-6-.7-.7-1.6-1.1-2.7-1-1.4.1-2.8.9-3.9 2.1-.9 1.1-3.1 4.5-2.3 7.5 0 .1 0 .2.1.3-2.3.3-4.2.2-4.4.1v1.5c.7.1 2.7.2 5.1-.2.5.7 1.3 1.2 2.3 1.6.1 0 2.4.8 4.5-.6.5-.3.9-.1 1.1 0 .4.2.7.6.7 1h1.4c0-.8-.6-1.7-1.4-2.2zm-8-1.7c-.5-2.2 1.1-5.1 2-6.2.8-.9 1.8-1.5 2.8-1.6h.1c.6 0 1.1.2 1.5.6 1.6 1.6-.4 3.9-.5 4-1.5 2-3.7 3-5.8 3.5l-.1-.3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.png
new file mode 100644
index 00000000..3d9fb230
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.svg
new file mode 100644
index 00000000..6c0ae5e0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M24 20h-24v1h24v-1zm-6-8l1-1 2 2 2-2 1 1-2 2 2 2-1 1-2-2-2 2-1-1 2-2zm-15.6 3.7c.9-.5 1.9-.5 2.7 0 1.5.9 3.1.4 3.1.4.4-.2.8-.4 1.1-.6-2.2-.6-4.4-1.8-6-3.9-1.1-1.2-2.5-3.9-.4-6 .7-.7 1.6-1.1 2.7-1 1.4.1 2.8.9 3.9 2.1.9 1.1 3.1 4.5 2.3 7.5 0 .1 0 .2-.1.3 2.3.3 4.2.2 4.4.1v1.5c-.7.1-2.7.2-5.1-.2-.5.7-1.3 1.2-2.3 1.6-.1 0-2.4.8-4.5-.6-.5-.3-.9-.1-1.1 0-.4.2-.7.6-.7 1h-1.4c0-.8.6-1.7 1.4-2.2zm8-1.7c.5-2.2-1.1-5.1-2-6.2-.8-.9-1.8-1.5-2.8-1.6h-.1c-.6 0-1.1.2-1.5.6-1.6 1.6.4 3.9.5 4 1.5 2 3.7 3 5.8 3.5l.1-.3z" id="path576"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.png
new file mode 100644
index 00000000..7181e6d4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.svg
new file mode 100644
index 00000000..e8b427b1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path id="a" d="M12.666 6h-1.372l-4.48 12H8.52l1.493-4h4l1.507 4h1.666l-4.52-12zm-2.28 7l1.617-4.333L13.637 13h-3.25z"/>
+ <g id="down">
+ <path id="arrow" d="M22 3l-3.5 6L15 3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.png
new file mode 100644
index 00000000..cc539f0e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.svg
new file mode 100644
index 00000000..e5e95196
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path id="a" d="M12.666 6h-1.372l-4.48 12H8.52l1.493-4h4l1.507 4h1.666l-4.52-12zm-2.28 7l1.617-4.333L13.637 13h-3.25z"/>
+ <g id="down">
+ <path id="arrow" d="M9 3L5.5 9 2 3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.png
new file mode 100644
index 00000000..51ccb89c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.svg
new file mode 100644
index 00000000..4d601281
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="special-character">
+ <path id="omega" d="M12 6.708c-.794 0-1.368.103-1.894.31-.525.207-.944.496-1.255.867-.311.366-.531.808-.66 1.327-.128.513-.192 1.08-.192 1.699 0 .513.058 1 .174 1.46.122.46.311.87.568 1.23.629.863 1.155 1.139 2.011 1.363l.247 3.035h-5v-3h.605l.531 1.354.394.053.605.044.751.035.456.009h.66l-.092-.894c-.629-.094-.811-.268-1.336-.522-.525-.26-.98-.59-1.365-.991-.379-.401-.675-.867-.889-1.398-.214-.537-.321-1.13-.321-1.779 0-.82.131-1.537.394-2.15.269-.619.656-1.133 1.163-1.54.507-.407 1.133-.711 1.878-.912.745-.206 1.6-.31 2.565-.31.959 0 1.811.103 2.556.31.751.201 1.38.504 1.887.912.507.407.892.92 1.154 1.54.269.614.403 1.33.403 2.15 0 .649-.107 1.242-.321 1.779-.214.531-.513.997-.898 1.398-.379.401-.831.732-1.356.991-.525.254-.707.428-1.336.522l-.092.894h.66l.447-.009.751-.035.605-.044.403-.053.531-1.354h.605v3h-5l.247-3.035c1.066-.11 1.337-.696 2.002-1.363.263-.36.452-.77.568-1.23.122-.46.183-.947.183-1.46 0-.619-.064-1.186-.192-1.699-.128-.519-.348-.962-.66-1.327-.311-.372-.73-.661-1.255-.867-.525-.206-1.1-.31-1.894-.31"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr.png
new file mode 100644
index 00000000..902d5482
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr.svg
new file mode 100644
index 00000000..f3fb8b31
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M19 20h-17l3-3v-11h17v11c0 1.7-1.3 3-3 3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl.png
new file mode 100644
index 00000000..133ef1d6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl.svg
new file mode 100644
index 00000000..fd9b7bd9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g586">
+ <path d="M5 20h17l-3-3v-11h-17v11c0 1.7 1.3 3 3 3z" id="path588"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.png
new file mode 100644
index 00000000..53e3f2cb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg
new file mode 100644
index 00000000..333c1e86
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M19 20h-17l3-3v-11h17v11c0 1.7-1.3 3-3 3z"/>
+ </g>
+ <path fill="#fff" d="M13 9h1v7h-1zm-3 3h7v1h-7z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.png
new file mode 100644
index 00000000..ef78b5ec
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg
new file mode 100644
index 00000000..4e6313f1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g598">
+ <path d="M5 20h17l-3-3v-11h-17v11c0 1.7 1.3 3 3 3z" id="path600"/>
+ </g>
+ <path d="M11 9h-1v7h1zm3 3h-7v1h7z" id="path602" fill="#fff"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr.png
new file mode 100644
index 00000000..ed649b84
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr.svg
new file mode 100644
index 00000000..c4b4a2f7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M20 9v9l2 2h-14v-11h12zm-17-5h12v4h-8v7h-6l2-2v-9z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl.png
new file mode 100644
index 00000000..fa3bd324
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl.svg
new file mode 100644
index 00000000..c452fbbd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g612">
+ <path d="M3 9v9l-2 2h14v-11h-12zm17-5h-12v4h8v7h6l-2-2v-9z" id="path614"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.png
new file mode 100644
index 00000000..445f2d45
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.svg
new file mode 100644
index 00000000..f58e8ce5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M12 7.4l1.7 3.6 4 .5-2.7 2.8.5 3.9-3.5-1.7-3.6 1.7.6-3.9-2.8-2.8 3.9-.5 1.9-3.6m0-3.4l-2.8 5.6-6.2.9 4.5 4.4-1.1 6.1 5.6-3 5.5 3-1-6.2 4.5-4.4-6.3-.9-2.7-5.5z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/star.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star.png
new file mode 100644
index 00000000..046bbf7e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/star.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star.svg
new file mode 100644
index 00000000..ea8c26c6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12 7.4l1.7 3.6 4 .5-2.7 2.8.5 3.9-3.5-1.7-3.6 1.7.6-3.9-2.8-2.8 3.9-.5 1.9-3.6m0-3.4l-2.8 5.6-6.2.9 4.5 4.4-1.1 6.1 5.6-3 5.5 3-1-6.2 4.5-4.4-6.3-.9-2.7-5.5z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.png
new file mode 100644
index 00000000..b7e20ef6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.svg
new file mode 100644
index 00000000..7bd06331
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12 6c3.9 0 7 3.1 7 7s-3.1 7-7 7-7-3.1-7-7 3.1-7 7-7m0-1c-4.4 0-8 3.6-8 8s3.6 8 8 8 8-3.6 8-8-3.6-8-8-8zm-3 5h6v6h-6z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.png
new file mode 100644
index 00000000..cab7a980
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.svg
new file mode 100644
index 00000000..480189f5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="strikethrough-a">
+ <path id="strikethrough" d="M6 11h12v1h-12v-1z"/>
+ <path id="a" d="M12.666 6h-1.372l-4.48 12h1.705l1.494-4h3.999l1.508 4h1.666l-4.52-12zm-2.28 7l1.617-4.333 1.634 4.333h-3.251z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.png
new file mode 100644
index 00000000..8aafe3f6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.svg
new file mode 100644
index 00000000..d57b652f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="strikethrough-s">
+ <path id="strikethrough" d="M6 12h12v1h-12v-1z"/>
+ <path id="s" d="M12.094 6c-1.133 0-2.076.287-2.75.9-.67.613-1 1.49-1 2.52 0 .889.221 1.602.719 2.13.498.528 1.279.91 2.312 1.14l.812.182v-.03c.656.147 1.128.375 1.375.63.252.256.375.607.375 1.11 0 .573-.172.97-.531 1.26-.358.291-.894.45-1.625.45-.477 0-.969-.074-1.469-.24-.502-.166-1.031-.417-1.562-.75l-.375-.238v2.158l.156.062c.58.237 1.143.417 1.688.54.549.121 1.07.18 1.562.18 1.286 0 2.297-.293 3-.9.709-.605 1.062-1.486 1.062-2.608 0-.943-.256-1.726-.781-2.312-.521-.592-1.305-1-2.344-1.229l-.812-.181c-.716-.148-1.204-.352-1.406-.539-.205-.203-.312-.485-.312-.935 0-.533.162-.899.5-1.17.342-.271.836-.42 1.531-.42.395 0 .818.052 1.25.181.433.127.908.333 1.406.6l.375.18v-2.041s-1.188-.383-1.688-.479c-.499-.098-.984-.151-1.468-.151z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.png
new file mode 100644
index 00000000..a0065cbb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.svg
new file mode 100644
index 00000000..8409dc15
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="strikethrough-y">
+ <path id="strikethrough" d="M6 11h12v1h-12v-1z"/>
+ <path id="a" d="M7 6h1.724l3.288 4.935 3.264-4.935h1.724l-4.194 6.285v5.715h-1.612v-5.715l-4.194-6.285"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr-invert.png
new file mode 100644
index 00000000..35e68374
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr-invert.svg
new file mode 100644
index 00000000..4fbd4ecd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M4 9h12v2h-12v-2zm0 3h8v2h-8v-2zm0-7h16v3h-16v-3zm16 14h-16v-3h16v3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.png
new file mode 100644
index 00000000..093b1a93
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.svg
new file mode 100644
index 00000000..acacc362
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M4 9h12v2h-12v-2zm0 3h8v2h-8v-2zm0-7h16v3h-16v-3zm16 14h-16v-3h16v3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl-invert.png
new file mode 100644
index 00000000..2ae83c7d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl-invert.svg
new file mode 100644
index 00000000..b18ddc46
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M20 9h-12v2h12v-2zm0 3h-8v2h8v-2zm0-7h-16v3h16v-3zm-16 14h16v-3h-16v3z" id="path624"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.png
new file mode 100644
index 00000000..e8aea5e2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.svg
new file mode 100644
index 00000000..c38a283f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M20 9h-12v2h12v-2zm0 3h-8v2h8v-2zm0-7h-16v3h16v-3zm-16 14h16v-3h-16v3z" id="path624"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.png
new file mode 100644
index 00000000..b9444904
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.svg
new file mode 100644
index 00000000..47eff5dd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g>
+ <path d="M20 19h-16v-2h16v2z"/>
+ </g>
+ <g>
+ <path d="M20 15h-16v-2h16v2z"/>
+ </g>
+ <g>
+ <path d="M20 11h-16v-2h16v2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/images/icons/remove-item.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.png
index 0d15c3b6..a49eaefc 100644
--- a/resources/lib/oojs-ui/images/icons/remove-item.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.svg
new file mode 100644
index 00000000..47e70d74
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.svg
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M20 19h-16v-2h16v2z"/>
+ </g>
+ <g>
+ <path d="M20 15h-16v-2h16v2z"/>
+ </g>
+ <g>
+ <path d="M20 11h-16v-2h16v2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr-invert.png
new file mode 100644
index 00000000..88d26c24
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr-invert.svg
new file mode 100644
index 00000000..d694cb15
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g>
+ <path d="M20 11h-16v-2h16v2zm-16 1h8v2h-8v-2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr.png
new file mode 100644
index 00000000..2c1e230d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr.svg
new file mode 100644
index 00000000..7f8822bc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M20 11h-16v-2h16v2zm-16 1h8v2h-8v-2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl-invert.png
new file mode 100644
index 00000000..279d80a2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl-invert.svg
new file mode 100644
index 00000000..86a52ee8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g654">
+ <path d="M4 11h16v-2h-16v2zm16 1h-8v2h8v-2z" id="path656"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl.png
new file mode 100644
index 00000000..5ce176cc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl.svg
new file mode 100644
index 00000000..fcb10bad
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g654">
+ <path d="M4 11h16v-2h-16v2zm16 1h-8v2h8v-2z" id="path656"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-invert.png
new file mode 100644
index 00000000..57ac8b74
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-invert.svg
new file mode 100644
index 00000000..d2e9786e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g>
+ <path d="M17 13h-13v-3h13v3zm-5 6h-8v-3h8v3zm-8-12v-3h16v3h-16z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-progressive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-progressive.png
new file mode 100644
index 00000000..5d9fca8a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-progressive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-progressive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-progressive.svg
new file mode 100644
index 00000000..be303204
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-progressive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #347BFF }</style>
+ <g>
+ <path d="M17 13h-13v-3h13v3zm-5 6h-8v-3h8v3zm-8-12v-3h16v3h-16z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr.png
new file mode 100644
index 00000000..533a915d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr.svg
new file mode 100644
index 00000000..76c80d20
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M17 13h-13v-3h13v3zm-5 6h-8v-3h8v3zm-8-12v-3h16v3h-16z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-invert.png
new file mode 100644
index 00000000..72d49068
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-invert.svg
new file mode 100644
index 00000000..6266319d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g666">
+ <path d="M7 13h13v-3h-13v3zm5 6h8v-3h-8v3zm8-12v-3h-16v3h16z" id="path668"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-progressive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-progressive.png
new file mode 100644
index 00000000..a51e389c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-progressive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-progressive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-progressive.svg
new file mode 100644
index 00000000..c5847b1f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-progressive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #347BFF }</style>
+ <g id="g666">
+ <path d="M7 13h13v-3h-13v3zm5 6h8v-3h-8v3zm8-12v-3h-16v3h16z" id="path668"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl.png
new file mode 100644
index 00000000..282c6527
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl.svg
new file mode 100644
index 00000000..308c2e62
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g666">
+ <path d="M7 13h13v-3h-13v3zm5 6h8v-3h-8v3zm8-12v-3h-16v3h16z" id="path668"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.png
new file mode 100644
index 00000000..f8b8766c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.svg
new file mode 100644
index 00000000..b7507daf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path id="x" d="M14 9l-2.354 3.406L14 16h-1.2L11 13.25 9.2 16H8l2.403-3.662L8 9h1.188l1.857 2.494L12.797 9H14z"/>
+ <path d="M18 13l-1 1v3l1 1h-1l-.527-.46L16 18h-1l1-1v-3l-1-1h1l.485.497L17 13z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.png
new file mode 100644
index 00000000..f01e11db
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.svg
new file mode 100644
index 00000000..9fe5325f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path id="x" d="M12 9l2.354 3.406L12 16h1.2l1.8-2.75L16.8 16H18l-2.403-3.662L18 9h-1.188l-1.857 2.494L13.203 9H12z"/>
+ <path d="M8 13l1 1v3l-1 1h1l.527-.46L10 18h1l-1-1v-3l1-1h-1l-.485.497L9 13z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.png
new file mode 100644
index 00000000..1f829c1b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.svg
new file mode 100644
index 00000000..f1b7caf3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M18.1 5.1c0 .3-.1.6-.3.9l-1.4 1.4-.9-.8 2.2-2.2c.3.1.4.4.4.7zm-.5 5.3h3.2c0 .3-.1.6-.4.9s-.5.4-.8.4h-2v-1.3zm-6.2-5v-3.2c.3 0 .6.1.9.4s.4.5.4.8v2h-1.3zm6.4 11.7c-.3 0-.6-.1-.8-.3l-1.4-1.4.8-.8 2.2 2.2c-.2.2-.5.3-.8.3zm-11.6-12.2c.3 0 .6.1.8.3l1.4 1.4-.8.9-2.2-2.3c.2-.2.5-.3.8-.3zm5.2 11.7h1.2v3.2c-.3 0-.6-.1-.9-.4s-.4-.5-.4-.8l.1-2zm-7-6.2h2v1.2h-3.2c0-.3.1-.6.4-.9s.5-.3.8-.3zm1.8 5.6l1.4-1.4.8.8-2.2 2.2c-.2-.2-.3-.5-.3-.8s.1-.6.3-.8z"/>
+ <circle cx="12" cy="11" r="4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.png
new file mode 100644
index 00000000..1e6f362f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.svg
new file mode 100644
index 00000000..a625fb90
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M5.9 5.1c0 .3.1.6.3.9l1.4 1.4.9-.8-2.2-2.2c-.3.1-.4.4-.4.7zm.5 5.3h-3.2c0 .3.1.6.4.9.3.3.5.4.8.4h2v-1.3zm6.2-5v-3.2c-.3 0-.6.1-.9.4-.3.3-.4.5-.4.8v2h1.3zm-6.4 11.7c.3 0 .6-.1.8-.3l1.4-1.4-.8-.8-2.2 2.2c.2.2.5.3.8.3zm11.6-12.2c-.3 0-.6.1-.8.3l-1.4 1.4.8.9 2.2-2.3c-.2-.2-.5-.3-.8-.3zm-5.2 11.7h-1.2v3.2c.3 0 .6-.1.9-.4.3-.3.4-.5.4-.8l-.1-2zm7-6.2h-2v1.2h3.2c0-.3-.1-.6-.4-.9-.3-.3-.5-.3-.8-.3zm-1.8 5.6l-1.4-1.4-.8.8 2.2 2.2c.2-.2.3-.5.3-.8 0-.3-.1-.6-.3-.8z" id="path678"/>
+ <circle cx="12" cy="11" r="4" id="circle680" transform="matrix(-1 0 0 1 24 0)"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.png
new file mode 100644
index 00000000..69fe6e7a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.svg
new file mode 100644
index 00000000..39f30a76
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path id="x" d="M14 9l-2.354 3.406L14 16h-1.2L11 13.25 9.2 16H8l2.403-3.662L8 9h1.188l1.857 2.494L12.797 9H14z"/>
+ <path d="M18 7l-1 1v3l1 1h-1l-.527-.46L16 12h-1l1-1V8l-1-1h1l.485.497L17 7z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.png
new file mode 100644
index 00000000..eac3d1d7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.svg
new file mode 100644
index 00000000..eabab21c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.svg
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path id="x" d="M12 9l2.354 3.406L12 16h1.2l1.8-2.75L16.8 16H18l-2.403-3.662L18 9h-1.188l-1.857 2.494L13.203 9H12z"/>
+ <path d="M8 7l1 1v3l-1 1h1l.527-.46L10 12h1l-1-1V8l1-1h-1l-.485.497L9 7z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.png
new file mode 100644
index 00000000..1389d3d8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.svg
new file mode 100644
index 00000000..15bb06a6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="table-caption">
+ <path id="caption" d="M6 6h12v3H6z"/>
+ <path id="table" d="M4 10v7h16v-7H4zm1 1h4v2H5v-2zm5 0h4v2h-4v-2zm5 0h4v2h-4v-2zM5 14h4v2H5v-2zm5 0h4v2h-4v-2zm5 0h4v2h-4v-2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr.png
new file mode 100644
index 00000000..dfd5e512
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr.svg
new file mode 100644
index 00000000..798ee4a1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="table-insert-column-ltr">
+ <path
+ d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
+ id="plus" />
+ <path
+ d="m 5,5 2,0 0,14 -2,0 z"
+ id="column" />
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl.png
new file mode 100644
index 00000000..1354a882
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl.svg
new file mode 100644
index 00000000..dfa33a08
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="table-insert-column-rtl">
+ <path
+ d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
+ id="plus" />
+ <path
+ d="m 17,5 2,0 0,14 -2,0 z"
+ id="column" />
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after.png
new file mode 100644
index 00000000..3d8091e8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after.svg
new file mode 100644
index 00000000..91d06644
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="table-insert-row-after">
+ <path
+ d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
+ id="plus" />
+ <path
+ d="m 5,17 14,0 0,2 -14,0 z"
+ id="row" />
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before.png
new file mode 100644
index 00000000..e357f90e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before.svg
new file mode 100644
index 00000000..4b71f2a8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before.svg
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="table-insert-row-before">
+ <path
+ d="m 13,9 -2,0 0,2 -2,0 0,2 2,0 0,2 2,0 0,-2 2,0 0,-2 -2,0 z"
+ id="plus" />
+ <path
+ d="m 5,5 14,0 0,2 -14,0 z"
+ id="row" />
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells.png
new file mode 100644
index 00000000..202a1209
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells.svg
new file mode 100644
index 00000000..6a8b77d8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells.svg
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24">
+ <g id="table-merge-cells">
+ <g id="merge-cell-left">
+ <path id="cell-border" d="m 4,7 0,9 7,0 0,-3 -1,0.834 L 10,15 5,15 5,8 10,8 10,9.167 11,10 11,7 z" />
+ <path id="arrow" d="m 8,9 0,2 -2,0 0,1 2,0 0,2 3,-2.5 z" />
+ </g>
+ <use id="merge-cell-right" xlink:href="#merge-cell-left" transform="matrix(-1,0,0,1,24,0)" />
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table.png
new file mode 100644
index 00000000..fb6b985b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table.svg
new file mode 100644
index 00000000..1ba8c440
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+
+ <g id="table-insert">
+ <path id="table" d="M4 5v13h16v-13zm2 2h5v4h-5zm7 0h5v4h-5zm-7 5h5v4h-5zm7 0h5v4h-5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.png
new file mode 100644
index 00000000..66af3753
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.svg
new file mode 100644
index 00000000..82171db6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #00AF89 }</style>
+ <g id="tag">
+ <path d="M18.748 11.717c.389.389.389 1.025 0 1.414l-4.949 4.95c-.389.389-1.025.389-1.414 0l-6.01-6.01c-.389-.389-.707-1.157-.707-1.707l-.001-4.364c0-.55.45-1 1-1h4.364c.55 0 1.318.318 1.707.707l6.01 6.01zm-10.644-4.261c-.579.576-.578 1.514-.001 2.093.578.577 1.516.577 2.095.001.576-.578.576-1.517 0-2.095-.581-.576-1.518-.577-2.094.001z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.png
new file mode 100644
index 00000000..1de90d48
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.svg
new file mode 100644
index 00000000..3d485128
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #D11D13 }</style>
+ <g id="tag">
+ <path d="M18.748 11.717c.389.389.389 1.025 0 1.414l-4.949 4.95c-.389.389-1.025.389-1.414 0l-6.01-6.01c-.389-.389-.707-1.157-.707-1.707l-.001-4.364c0-.55.45-1 1-1h4.364c.55 0 1.318.318 1.707.707l6.01 6.01zm-10.644-4.261c-.579.576-.578 1.514-.001 2.093.578.577 1.516.577 2.095.001.576-.578.576-1.517 0-2.095-.581-.576-1.518-.577-2.094.001z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.png
new file mode 100644
index 00000000..c2334293
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.svg
new file mode 100644
index 00000000..e5734295
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="tag">
+ <path d="M18.748 11.717c.389.389.389 1.025 0 1.414l-4.949 4.95c-.389.389-1.025.389-1.414 0l-6.01-6.01c-.389-.389-.707-1.157-.707-1.707l-.001-4.364c0-.55.45-1 1-1h4.364c.55 0 1.318.318 1.707.707l6.01 6.01zm-10.644-4.261c-.579.576-.578 1.514-.001 2.093.578.577 1.516.577 2.095.001.576-.578.576-1.517 0-2.095-.581-.576-1.518-.577-2.094.001z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.png
new file mode 100644
index 00000000..a6759e21
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.svg
new file mode 100644
index 00000000..f52e06ce
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #347BFF }</style>
+ <g id="tag">
+ <path d="M18.748 11.717c.389.389.389 1.025 0 1.414l-4.949 4.95c-.389.389-1.025.389-1.414 0l-6.01-6.01c-.389-.389-.707-1.157-.707-1.707l-.001-4.364c0-.55.45-1 1-1h4.364c.55 0 1.318.318 1.707.707l6.01 6.01zm-10.644-4.261c-.579.576-.578 1.514-.001 2.093.578.577 1.516.577 2.095.001.576-.578.576-1.517 0-2.095-.581-.576-1.518-.577-2.094.001z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.png
new file mode 100644
index 00000000..77fc366a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.svg
new file mode 100644
index 00000000..337adb63
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FF5D00 }</style>
+ <g id="tag">
+ <path d="M18.748 11.717c.389.389.389 1.025 0 1.414l-4.949 4.95c-.389.389-1.025.389-1.414 0l-6.01-6.01c-.389-.389-.707-1.157-.707-1.707l-.001-4.364c0-.55.45-1 1-1h4.364c.55 0 1.318.318 1.707.707l6.01 6.01zm-10.644-4.261c-.579.576-.578 1.514-.001 2.093.578.577 1.516.577 2.095.001.576-.578.576-1.517 0-2.095-.581-.576-1.518-.577-2.094.001z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.png
new file mode 100644
index 00000000..8e100fcb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/tag.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.svg
index 1d61b814..534824c8 100644
--- a/resources/lib/oojs-ui/images/icons/tag.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="tag" opacity=".75">
+ <g id="tag">
<path d="M18.748 11.717c.389.389.389 1.025 0 1.414l-4.949 4.95c-.389.389-1.025.389-1.414 0l-6.01-6.01c-.389-.389-.707-1.157-.707-1.707l-.001-4.364c0-.55.45-1 1-1h4.364c.55 0 1.318.318 1.707.707l6.01 6.01zm-10.644-4.261c-.579.576-.578 1.514-.001 2.093.578.577 1.516.577 2.095.001.576-.578.576-1.517 0-2.095-.581-.576-1.518-.577-2.094.001z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.png
new file mode 100644
index 00000000..dd52d120
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.svg
new file mode 100644
index 00000000..6b594b29
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M24 6h-4v-4h-2v4h-4v2h4v4h2v-4h4z"/>
+ </g>
+ <path d="M19 13v7h-16c-1.1 0-2-.9-2-2v-11h12v-1h-13v12c0 1.7 1.3 3 3 3h17v-8h-1z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.png
new file mode 100644
index 00000000..08b1613c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.svg
new file mode 100644
index 00000000..36b25a3e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g690">
+ <path d="M0 6h4v-4h2v4h4v2h-4v4h-2v-4h-4z" id="path692"/>
+ </g>
+ <path d="M5 13v7h16c1.1 0 2-.9 2-2v-11h-12v-1h13v12c0 1.7-1.3 3-3 3h-17v-8h1z" id="path694"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright.png
new file mode 100644
index 00000000..ffd190a1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright.svg
new file mode 100644
index 00000000..62526a03
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="text-dir-ltr">
+ <path d="M7 7h-2v-1h2l.469.5.531-.5h2v1h-2v10h2v1h-2l-.5-.531-.5.531h-2v-1h2zM13.976 16v-2h-2.976v-4h2.976v-1.956l6.024 3.978z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft.png
new file mode 100644
index 00000000..214f8d14
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft.svg
new file mode 100644
index 00000000..913bbfd6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="text-dir-rtl">
+ <path d="M17 17h2v1h-2l-.469-.5-.531.5h-2v-1h2v-10h-2v-1h2l.5.531.5-.531h2v1h-2zM10.024 8v2h2.976v4h-2.976v1.956l-6.024-3.978z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.png
new file mode 100644
index 00000000..4484496f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.svg
new file mode 100644
index 00000000..0198c355
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="text-style">
+ <path id="a" d="M15.296 18h2.789l-1.14-12h-2.789l-8.156 12h2.789l2.039-3h4.183l.285 3zm-3.109-5l2.311-3.4.323 3.4h-2.634z"/>
+ <path id="underline" d="M6 19h12v1h-12v-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.png
new file mode 100644
index 00000000..10254613
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.svg
new file mode 100644
index 00000000..7740e43e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M11.1 13.1c-1.8-2.1-2.7-4.3-3-5.1h4.7l.7-2h-5.5v-3h-2v3h-5v2h5c-.2.9-1.3 4.8-5.1 7.6l1.2 1.6c2.7-2 4.3-4.5 5.1-6.4.7 1.3 1.7 3 3.2 4.5l.7-2.2zm1.4 6.9l1.3-4h5.3l1.3 4h2.2l-4.6-14h-3l-4.7 14h2.2zm4-12l2 6h-4l2-6z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.png
new file mode 100644
index 00000000..17f543ca
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.svg
new file mode 100644
index 00000000..c78e6222
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12.4 13.1c1.8-2.1 2.7-4.3 3-5.1h-4.7l-.7-2h5.5v-3h2v3h5v2h-5c.2.9 1.3 4.8 5.1 7.6l-1.2 1.6c-2.7-2-4.3-4.5-5.1-6.4-.7 1.3-1.7 3-3.2 4.5l-.7-2.2zm-1.4 6.9l-1.3-4h-5.3l-1.3 4h-2.2l4.6-14h3l4.7 14h-2.2zm-4-12l-2 6h4l-2-6z" id="path704"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.png
new file mode 100644
index 00000000..d730765d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.svg
new file mode 100644
index 00000000..baa31f6c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M6 8c0-1.1.9-2 2-2h2l1-1h2l1 1h2c1.1 0 2 .9 2 2h-12zm1 1h10l-1 11h-8z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.png
new file mode 100644
index 00000000..dfee886c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.svg
new file mode 100644
index 00000000..f5914312
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M6 8c0-1.1.9-2 2-2h2l1-1h2l1 1h2c1.1 0 2 .9 2 2h-12zm1 1h10l-1 11h-8z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr-invert.png
new file mode 100644
index 00000000..bc977a77
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr-invert.svg
new file mode 100644
index 00000000..20cd2991
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g>
+ <path d="M20.5 20.5l-15.5-15.5-1 1 3 3 1 11h8l.2-1.8 3.3 3.3zm-3.5-11.5h-6l5.5 5.5zm1-1c0-1.1-.9-2-2-2h-2l-1-1h-2l-1 1h-2l2 2h8z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr.png
new file mode 100644
index 00000000..594836ec
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr.svg
new file mode 100644
index 00000000..0731f056
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M20.5 20.5l-15.5-15.5-1 1 3 3 1 11h8l.2-1.8 3.3 3.3zm-3.5-11.5h-6l5.5 5.5zm1-1c0-1.1-.9-2-2-2h-2l-1-1h-2l-1 1h-2l2 2h8z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl-invert.png
new file mode 100644
index 00000000..162d9a92
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl-invert.svg
new file mode 100644
index 00000000..aebedec7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="g714">
+ <path d="M4 20.5l15.5-15.5 1 1-3 3-1 11h-8l-.2-1.8-3.3 3.3zm3.5-11.5h6l-5.5 5.5zm-1-1c0-1.1.9-2 2-2h2l1-1h2l1 1h2l-2 2h-8z" id="path716"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.png
new file mode 100644
index 00000000..182e56d9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.svg
new file mode 100644
index 00000000..2a92cbef
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g714">
+ <path d="M4 20.5l15.5-15.5 1 1-3 3-1 11h-8l-.2-1.8-3.3 3.3zm3.5-11.5h6l-5.5 5.5zm-1-1c0-1.1.9-2 2-2h2l1-1h2l1 1h2l-2 2h-8z" id="path716"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-destructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-destructive.png
new file mode 100644
index 00000000..b4c13665
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-destructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-destructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-destructive.svg
new file mode 100644
index 00000000..97fcdc4c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-destructive.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #D11D13 }</style>
+ <path d="M12 9v-2s0-5-4.5-5-4.5 5-4.5 5h2s0-3 2.5-3 2.5 3 2.5 3v2h-3v7c0 1.7 1.3 3 3 3h10v-10z" id="path726"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-invert.png
new file mode 100644
index 00000000..3a0bc75b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-invert.svg
new file mode 100644
index 00000000..b496a065
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M12 9v-2s0-5-4.5-5-4.5 5-4.5 5h2s0-3 2.5-3 2.5 3 2.5 3v2h-3v7c0 1.7 1.3 3 3 3h10v-10z" id="path726"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.png
new file mode 100644
index 00000000..8f261a88
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.svg
new file mode 100644
index 00000000..66c024a9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12 9v-2s0-5-4.5-5-4.5 5-4.5 5h2s0-3 2.5-3 2.5 3 2.5 3v2h-3v7c0 1.7 1.3 3 3 3h10v-10z" id="path726"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-destructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-destructive.png
new file mode 100644
index 00000000..03d91f22
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-destructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-destructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-destructive.svg
new file mode 100644
index 00000000..a52f0fe3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-destructive.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #D11D13 }</style>
+ <path d="M11 9v-2s0-5 4.5-5 4.5 5 4.5 5h-2s0-3-2.5-3-2.5 3-2.5 3v2h3v7c0 1.7-1.3 3-3 3h-10v-10z" id="path726"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-invert.png
new file mode 100644
index 00000000..b8233255
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-invert.svg
new file mode 100644
index 00000000..814af1dd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M11 9v-2s0-5 4.5-5 4.5 5 4.5 5h-2s0-3-2.5-3-2.5 3-2.5 3v2h3v7c0 1.7-1.3 3-3 3h-10v-10z" id="path726"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.png
new file mode 100644
index 00000000..e683c521
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.svg
new file mode 100644
index 00000000..07cecbfe
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M11 9v-2s0-5 4.5-5 4.5 5 4.5 5h-2s0-3-2.5-3-2.5 3-2.5 3v2h3v7c0 1.7-1.3 3-3 3h-10v-10z" id="path726"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-invert.png
new file mode 100644
index 00000000..03a56873
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-invert.svg
new file mode 100644
index 00000000..b66ce2a8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M21 11l-6-1-3-6-3 6-6 1 4 4-1 6 6-3 6 3-1-6 4-4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar.png
new file mode 100644
index 00000000..bdb1c4fe
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar.svg
new file mode 100644
index 00000000..724d1901
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M21 11l-6-1-3-6-3 6-6 1 4 4-1 6 6-3 6 3-1-6 4-4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.png
new file mode 100644
index 00000000..81713bdd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.svg
new file mode 100644
index 00000000..dd6dde36
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="underline-a">
+ <path id="a" d="M14.424 16h2.076l-3.463-10h-2.077l-3.46 10h2.077l.627-2h3.604l.616 2zm-3.921-3.623l1.496-4.379 1.511 4.379h-3z"/>
+ <path id="underline" d="M7 17h10v1h-10v-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.png
new file mode 100644
index 00000000..c4eb2a21
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.svg
new file mode 100644
index 00000000..fbd7c147
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="underline-u">
+ <path id="u" d="M8 6h2v5.959c-.104 1.707.695 2.002 2 2.041 1.777.062 2.002-.879 2-2.041v-5.959h2v6.123c0 1.279-.338 2.245-1.016 2.898-.672.651-1.666.979-2.98.979-1.32 0-2.319-.326-2.996-.979-.672-.653-1.008-1.619-1.008-2.898v-6.123"/>
+ <path id="underline" d="M7 17h10v1h-10v-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.png
new file mode 100644
index 00000000..1b655891
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.svg
new file mode 100644
index 00000000..9e5e72f6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M12 8l8 10h-16z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr.png
new file mode 100644
index 00000000..fa2da24e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr.svg
new file mode 100644
index 00000000..18879e32
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M10 13c0 1.7 1.3 3 3 3v-7h3l-4.5-5-4.5 5h3v4zm7 0v5h-10c-.6 0-1-.4-1-1v-4h-2v4c0 1.9 1.3 3 3 3h12v-7h-2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl.png
new file mode 100644
index 00000000..1ac6106a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl.svg
new file mode 100644
index 00000000..7a3535ba
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g736">
+ <path d="M13 13c0 1.7-1.3 3-3 3v-7h-3l4.5-5 4.5 5h-3v4zm-7 0v5h10c.6 0 1-.4 1-1v-4h2v4c0 1.9-1.3 3-3 3h-12v-7h2z" id="path738"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.png
new file mode 100644
index 00000000..bc94f180
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.svg
new file mode 100644
index 00000000..5dcc3179
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M16 5h-12v12c0 1.7 1.3 3 3 3h12v-12c0-1.7-1.3-3-3-3zm-2 4c.7 0 1.2.6 1.2 1.2s-.6 1.2-1.2 1.2-1.2-.6-1.2-1.2.5-1.2 1.2-1.2zm-5 0c.7 0 1.2.6 1.2 1.2s-.5 1.3-1.2 1.3-1.2-.6-1.2-1.2.5-1.3 1.2-1.3zm7 5.4c0 .2-.1.3-.3.5-.7.6-1.6 1-2.6 1.3s-2.1.2-3.1 0-2-.9-2.7-1.5c-.1-.1-.2-.3-.2-.4s.1-.3.2-.4c.1-.1.3-.2.4-.2.2 0 .3.1.4.2.5.5 1.2.9 2.1 1.1s1.7.2 2.6 0 1.6-.5 2.1-1c.1-.1.3-.2.4-.2s.3.1.5.2.2.2.2.4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.png
new file mode 100644
index 00000000..6fb01ceb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.svg
new file mode 100644
index 00000000..a5e4dc95
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M7 5h12v12c0 1.7-1.3 3-3 3h-12v-12c0-1.7 1.3-3 3-3zm2 4c-.7 0-1.2.6-1.2 1.2s.6 1.2 1.2 1.2 1.2-.6 1.2-1.2-.5-1.2-1.2-1.2zm5 0c-.7 0-1.2.6-1.2 1.2s.5 1.3 1.2 1.3 1.2-.6 1.2-1.2-.5-1.3-1.2-1.3zm-7 5.4c0 .2.1.3.3.5.7.6 1.6 1 2.6 1.3 1 .3 2.1.2 3.1 0s2-.9 2.7-1.5c.1-.1.2-.3.2-.4 0-.1-.1-.3-.2-.4-.1-.1-.3-.2-.4-.2-.2 0-.3.1-.4.2-.5.5-1.2.9-2.1 1.1-.9.2-1.7.2-2.6 0-.9-.2-1.6-.5-2.1-1-.1-.1-.3-.2-.4-.2-.1 0-.3.1-.5.2s-.2.2-.2.4z" id="path748"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.png
new file mode 100644
index 00000000..3c3fb473
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.svg
new file mode 100644
index 00000000..e9687fa6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g4">
+ <g id="g6">
+ <path d="M11.5 13c1.7 0 3.5-2 3.5-5 0-.1 0-4-3.5-4s-3.5 3.9-3.5 4c0 3 1.8 5 3.5 5zm3.5-1c-.4.7-1.7 2-3.5 2s-3.2-1.3-3.5-2h-2c-1.1 0-2 .9-2 2v6h15v-6c0-1.1-.9-2-2-2h-2z" id="path8"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.png
new file mode 100644
index 00000000..7e4cfd1a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.svg
new file mode 100644
index 00000000..bb5b0968
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M16 5h-12v12c0 1.7 1.3 3 3 3h12v-12c0-1.7-1.3-3-3-3zm-9.3 5.4c-.5-.4-.7-.8-.7-1.4.6.6 1.5.9 2.5.9s1.9-.3 2.5-.9c0 .6-.2 1-.7 1.4-.5.4-1.1.6-1.8.6s-1.3-.2-1.8-.6zm8.4 4.3c0 .2-.1.3-.3.4-1 .6-2.2.9-3.5.9-1.2 0-2.3-.3-3.3-1-.2-.1-.2-.2-.3-.4s0-.3.1-.5.2-.2.4-.3.3 0 .5.1c.8.5 1.7.8 2.8.8s2-.2 2.8-.7c.1-.1.3-.1.5-.1s.3.1.4.3l-.1.5zm1.2-4.3c-.5.4-1.1.6-1.8.6s-1.3-.2-1.8-.6-.7-.8-.7-1.4c.6.6 1.5.9 2.5.9s1.9-.3 2.5-.9c0 .6-.2 1-.7 1.4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.png
new file mode 100644
index 00000000..d71a08b8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.svg
new file mode 100644
index 00000000..4a9fd0d7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M7 5h12v12c0 1.7-1.3 3-3 3h-12v-12c0-1.7 1.3-3 3-3zm9.3 5.4c.5-.4.7-.8.7-1.4-.6.6-1.5.9-2.5.9s-1.9-.3-2.5-.9c0 .6.2 1 .7 1.4.5.4 1.1.6 1.8.6s1.3-.2 1.8-.6zm-8.4 4.3c0 .2.1.3.3.4 1 .6 2.2.9 3.5.9 1.2 0 2.3-.3 3.3-1 .2-.1.2-.2.3-.4.1-.2 0-.3-.1-.5s-.2-.2-.4-.3c-.2-.1-.3 0-.5.1-.8.5-1.7.8-2.8.8-1.1 0-2-.2-2.8-.7-.1-.1-.3-.1-.5-.1s-.3.1-.4.3l.1.5zm-1.2-4.3c.5.4 1.1.6 1.8.6s1.3-.2 1.8-.6c.5-.4.7-.8.7-1.4-.6.6-1.5.9-2.5.9s-1.9-.3-2.5-.9c0 .6.2 1 .7 1.4z" id="path758"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.png
new file mode 100644
index 00000000..952410a8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.svg
new file mode 100644
index 00000000..f516539c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M5 6v11l-3 3h17c1.7 0 3-1.3 3-3v-11h-17zm11.2 2.5c.7 0 1.2.6 1.2 1.2s-.5 1.3-1.2 1.3-1.2-.6-1.2-1.2.6-1.3 1.2-1.3zm-5.4 0c.7 0 1.2.6 1.2 1.2s-.6 1.3-1.2 1.3-1.2-.6-1.2-1.2.5-1.3 1.2-1.3zm2.7 8.5c-5.1 0-6-5-6-5s2 1 6 1l6-1s-1 5-6 5z" id="path6"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.png
new file mode 100644
index 00000000..1a0983d1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.svg
new file mode 100644
index 00000000..8963fafc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M19 6v11l3 3h-17c-1.7 0-3-1.3-3-3v-11h17zm-11.2 2.5c-.7 0-1.2.6-1.2 1.2s.5 1.3 1.2 1.3 1.2-.6 1.2-1.2-.6-1.3-1.2-1.3zm5.4 0c-.7 0-1.2.6-1.2 1.2s.6 1.3 1.2 1.3 1.2-.6 1.2-1.2-.5-1.3-1.2-1.3zm-2.7 8.5c5.1 0 6-5 6-5s-2 1-6 1l-6-1s1 5 6 5z" id="path770"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact-invert.png
new file mode 100644
index 00000000..8e0abb0d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact-invert.svg
new file mode 100644
index 00000000..ed1913ab
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact-invert.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="viewCompact">
+ <circle cx="6" cy="6" r="2"/>
+ <circle cx="12" cy="6" r="2"/>
+ <circle cx="18" cy="6" r="2"/>
+ <circle cx="6" cy="12" r="2"/>
+ <circle cx="12" cy="12" r="2"/>
+ <circle cx="18" cy="12" r="2"/>
+ <circle cx="6" cy="18" r="2"/>
+ <circle cx="12" cy="18" r="2"/>
+ <circle cx="18" cy="18" r="2"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact.png
new file mode 100644
index 00000000..bc4bc260
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact.svg
new file mode 100644
index 00000000..d96a2e3f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewCompact.svg
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="viewCompact">
+ <circle cx="6" cy="6" r="2"/>
+ <circle cx="12" cy="6" r="2"/>
+ <circle cx="18" cy="6" r="2"/>
+ <circle cx="6" cy="12" r="2"/>
+ <circle cx="12" cy="12" r="2"/>
+ <circle cx="18" cy="12" r="2"/>
+ <circle cx="6" cy="18" r="2"/>
+ <circle cx="12" cy="18" r="2"/>
+ <circle cx="18" cy="18" r="2"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr-invert.png
new file mode 100644
index 00000000..35bbc8d2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr-invert.svg
new file mode 100644
index 00000000..14e435db
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr-invert.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="viewDetails">
+ <circle cx="5.5" cy="8.5" r="2.5"/>
+ <path d="M10 6h12v1H10zM10 8h9v1h-9zM10 10h4v1h-4z"/>
+ <circle cx="5.5" cy="16.5" r="2.5"/>
+ <path d="M10 14h12v1H10zM10 16h9v1h-9zM10 18h4v1h-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.png
new file mode 100644
index 00000000..4ab5394b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.svg
new file mode 100644
index 00000000..4f5f9b3d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="viewDetails">
+ <circle cx="5.5" cy="8.5" r="2.5"/>
+ <path d="M10 6h12v1H10zM10 8h9v1h-9zM10 10h4v1h-4z"/>
+ <circle cx="5.5" cy="16.5" r="2.5"/>
+ <path d="M10 14h12v1H10zM10 16h9v1h-9zM10 18h4v1h-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl-invert.png
new file mode 100644
index 00000000..c45dd114
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl-invert.svg
new file mode 100644
index 00000000..f4838fe5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl-invert.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="viewDetails">
+ <circle cx="18.5" cy="8.5" r="2.5"/>
+ <path d="M14 6H2v1h12zm0 2H5v1h9zm0 2h-4v1h4z"/>
+ <circle cx="18.5" cy="16.5" r="2.5"/>
+ <path d="M14 14H2v1h12zm0 2H5v1h9zm0 2h-4v1h4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl.png
new file mode 100644
index 00000000..46587ecf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl.svg
new file mode 100644
index 00000000..f43b05f1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-rtl.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="viewDetails">
+ <circle cx="18.5" cy="8.5" r="2.5"/>
+ <path d="M14 6H2v1h12zm0 2H5v1h9zm0 2h-4v1h4z"/>
+ <circle cx="18.5" cy="16.5" r="2.5"/>
+ <path d="M14 14H2v1h12zm0 2H5v1h9zm0 2h-4v1h4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.png
new file mode 100644
index 00000000..118e4687
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.svg
new file mode 100644
index 00000000..ae0d94e2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <path d="M0 10v8h2.3c.3.6 1 1 1.7 1h4c1.5 0 2.7-.8 3-2h2c.3 1.2 1.5 2 3 2h4c.7 0 1.4 0 1.7-1H24v-8zm10 6c0 1-.4 2-2 2H4c-.6 0-1-.4-1-1v-3c0-.6.4-1 1-1h5c.6 0 1 .4 1 1zm11 1c0 .6-.4 1-1 1h-4c-1.6 0-2-1-2-2v-2c0-.6.4-1 1-1h5c.6 0 1 .4 1 1z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator.png
new file mode 100644
index 00000000..e1afbaef
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator.svg
new file mode 100644
index 00000000..ae6ba27a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M0 10v8h2.3c.3.6 1 1 1.7 1h4c1.5 0 2.7-.8 3-2h2c.3 1.2 1.5 2 3 2h4c.7 0 1.4 0 1.7-1H24v-8zm10 6c0 1-.4 2-2 2H4c-.6 0-1-.4-1-1v-3c0-.6.4-1 1-1h5c.6 0 1 .4 1 1zm11 1c0 .6-.4 1-1 1h-4c-1.6 0-2-1-2-2v-2c0-.6.4-1 1-1h5c.6 0 1 .4 1 1z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr.png
new file mode 100644
index 00000000..4b94c1ae
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr.svg
new file mode 100644
index 00000000..79c7d5ca
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M13 14h5v1h-5v-1zm0 3h5v-1h-5v1zm0 1h5v1h-5v-1zm-1-5v3l-5 3 1-6-4-3 6-1 2-5s1.9 5 2 5l6 1-4 3h-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.png
new file mode 100644
index 00000000..f9cc5ea7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.svg
new file mode 100644
index 00000000..6bbc2fa2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g780">
+ <path d="M11 14h-5v1h5v-1zm0 3h-5v-1h5v1zm0 1h-5v1h5v-1zm1-5v3l5 3-1-6 4-3-6-1-2-5s-1.9 5-2 5l-6 1 4 3h4z" id="path782"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.png
new file mode 100644
index 00000000..4b15161c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.svg
new file mode 100644
index 00000000..eebd9b1a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M23 5h-4v2h2v10h-2v2h4z"/>
+ </g>
+ <g>
+ <path d="M18 5h-4v2h2v10h-2v2h4z"/>
+ </g>
+ <g>
+ <path d="M2 5h4v2h-2v10h2v2h-4z"/>
+ </g>
+ <g>
+ <path d="M7 5h4v2h-2v10h2v2h-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.png
new file mode 100644
index 00000000..41743b3a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.svg
new file mode 100644
index 00000000..c606becd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M15 9l.7-1.8c.9.4 1.8.7 2.4.9l-.6 1.7v.2l-2.5-1zm-4.3-1.9l.8-1.8c1.2.5 2.6 1.1 3 1.4l-.8 1.8-3-1.4zm-5.9-1c-.8 0-1.4.2-2 .6l-1.1-1.7c.9-.6 1.9-.9 3.1-.9v2zm-4.3.7l1.8.8c-.3.7-.3 1.3-.1 1.8l-1.9.7c-.3-1.2-.3-2.3.2-3.3zm4.2 5.4l-1.3 1.5c-1-1-1.7-1.6-2-2l1.5-1.3c.7.8 1.3 1.4 1.8 1.8zm7.3 4.3c0 1.9-1.6 3.5-3.5 3.5s-3.5-1.6-3.5-3.5 1.6-3.5 3.5-3.5 3.5 1.6 3.5 3.5z"/>
+ </g>
+ <path d="M24 8l-1-1-1.5 1.5-1.5-1.5-1 1 1.5 1.5-1.5 1.5 1 1 1.5-1.5 1.5 1.5 1-1-1.5-1.5z"/>
+ <circle cx="8" cy="5" r="2"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl.png
new file mode 100644
index 00000000..29dc26b9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl.svg
new file mode 100644
index 00000000..f304f6ed
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g id="g792">
+ <path d="M9.095 9l-.7-1.8c-.9.4-1.8.7-2.4.9l.6 1.7v.2l2.5-1zm4.3-1.9l-.8-1.8c-1.2.5-2.6 1.1-3 1.4l.8 1.8 3-1.4zm5.9-1c.8 0 1.4.2 2 .6l1.1-1.7c-.9-.6-1.9-.9-3.1-.9v2zm4.3.7l-1.8.8c.3.7.3 1.3.1 1.8l1.9.7c.3-1.2.3-2.3-.2-3.3zm-4.2 5.4l1.3 1.5c1-1 1.7-1.6 2-2l-1.5-1.3c-.7.8-1.3 1.4-1.8 1.8zm-7.3 4.3c0 1.9 1.6 3.5 3.5 3.5s3.5-1.6 3.5-3.5-1.6-3.5-3.5-3.5-3.5 1.6-3.5 3.5z" id="path794"/>
+ </g>
+ <path d="M.095 8l1-1 1.5 1.5 1.5-1.5 1 1-1.5 1.5 1.5 1.5-1 1-1.5-1.5-1.5 1.5-1-1 1.5-1.5z" id="path796"/>
+ <circle cx="8" cy="5" r="2" id="circle798" transform="matrix(-1 0 0 1 24.095 0)"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.png
new file mode 100644
index 00000000..1c6ed1f3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.svg
new file mode 100644
index 00000000..0aeb6168
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><style>* { fill: #FFFFFF }</style>
+ <g id="window">
+ <path id="title" d="M7 10h10v1h-10z"/>
+ <path id="frame" d="M16 19h-8c-2.206 0-4-1.794-4-4v-6c0-2.206 1.794-4 4-4h8c2.206 0 4 1.794 4 4v6c0 2.206-1.794 4-4 4zm-8-12c-1.103 0-2 .897-2 2v6c0 1.103.897 2 2 2h8c1.103 0 2-.897 2-2v-6c0-1.103-.897-2-2-2h-8z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/window.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window.png
new file mode 100644
index 00000000..db726a19
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/icons/window.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window.svg
index 44f7ba75..cd3b76c2 100644
--- a/resources/lib/oojs-ui/images/icons/window.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
- <g id="window" opacity=".75">
+ <g id="window">
<path id="title" d="M7 10h10v1h-10z"/>
<path id="frame" d="M16 19h-8c-2.206 0-4-1.794-4-4v-6c0-2.206 1.794-4 4-4h8c2.206 0 4 1.794 4 4v6c0 2.206-1.794 4-4 4zm-8-12c-1.103 0-2 .897-2 2v6c0 1.103.897 2 2 2h8c1.103 0 2-.897 2-2v-6c0-1.103-.897-2-2-2h-8z"/>
</g>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.png
new file mode 100644
index 00000000..28c8704c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.svg
new file mode 100644
index 00000000..cd666495
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
+ <g id="alert">
+ <path d="M6 12c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6zm-1-5h2v-5h-2zm0 3h2v-2h-2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert.png
new file mode 100644
index 00000000..5bf08278
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/indicators/alert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert.svg
index e2e49a87..d9dc6a87 100644
--- a/resources/lib/oojs-ui/images/indicators/alert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="alert" opacity=".75">
+ <g id="alert">
<path d="M6 12c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6zm-1-5h2v-5h-2zm0 3h2v-2h-2z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down-invert.png
new file mode 100644
index 00000000..f18841d4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down-invert.svg
new file mode 100644
index 00000000..847f9358
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down-invert.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve"><style>* { fill: #FFFFFF }</style>
+<g id="down">
+ <path id="arrow" d="M883.3,341H116.7L500,724.3l0,0l0,0L883.3,341"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.png
new file mode 100644
index 00000000..15ec5861
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.svg
new file mode 100644
index 00000000..17380577
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="0 0 1000 1000" enable-background="new 0 0 1000 1000" xml:space="preserve">
+<g id="down">
+ <path id="arrow" d="M883.3,341H116.7L500,724.3l0,0l0,0L883.3,341"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr-invert.png
new file mode 100644
index 00000000..22bf8977
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr-invert.svg
new file mode 100644
index 00000000..2a91c027
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr-invert.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve"><style>* { fill: #FFFFFF }</style>
+<g id="ltr">
+ <path id="arrow" d="M-489,496v10l5-5h0h0L-489,496"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.png
new file mode 100644
index 00000000..44403291
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.svg
new file mode 100644
index 00000000..fb366e64
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve">
+<g id="ltr">
+ <path id="arrow" d="M-489,496v10l5-5h0h0L-489,496"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl-invert.png
new file mode 100644
index 00000000..4f3c9d16
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl-invert.svg
new file mode 100644
index 00000000..3cce872e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl-invert.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve"><style>* { fill: #FFFFFF }</style>
+<g id="rtl">
+ <path id="arrow" d="M-485,506v-10l-5,5h0h0L-485,506"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.png
new file mode 100644
index 00000000..5f1f868f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.svg
new file mode 100644
index 00000000..62b6bb50
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve">
+<g id="rtl">
+ <path id="arrow" d="M-485,506v-10l-5,5h0h0L-485,506"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up-invert.png
new file mode 100644
index 00000000..e6fad56e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up-invert.svg
new file mode 100644
index 00000000..50da8de0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up-invert.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve"><style>* { fill: #FFFFFF }</style>
+<g id="up">
+ <path id="arrow" d="M-492,503h10l-5-5v0v0L-492,503"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.png
new file mode 100644
index 00000000..38d01c7d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.svg
new file mode 100644
index 00000000..20e734fb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<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"
+ viewBox="-493 495 12 12" enable-background="new -493 495 12 12" xml:space="preserve">
+<g id="up">
+ <path id="arrow" d="M-492,503h10l-5-5v0v0L-492,503"/>
+</g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.png
new file mode 100644
index 00000000..614c6e86
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.svg
new file mode 100644
index 00000000..30baa50c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
+ <g id="required">
+ <path d="M5 1h2v10h-2zM9.83 2.634l1 1.732-8.66 5-1-1.732zM1.17 4.366l1-1.732 8.66 5-1 1.732z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required.png
new file mode 100644
index 00000000..45eb03b6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/indicators/required.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required.svg
index 45035f4e..969fa2d8 100644
--- a/resources/lib/oojs-ui/images/indicators/required.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required.svg
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
- <g id="required" opacity=".75">
+ <g id="required">
<path d="M5 1h2v10h-2zM9.83 2.634l1 1.732-8.66 5-1-1.732zM1.17 4.366l1-1.732 8.66 5-1 1.732z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr-invert.png
new file mode 100644
index 00000000..2840bef1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr-invert.svg
new file mode 100644
index 00000000..f46b1eeb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
+ <g id="search">
+ <path id="path3051" d="M10.369 9.474l-2.374-2.375-.169-.099c.403-.566.643-1.26.643-2.009-.001-1.92-1.558-3.477-3.477-3.477-1.921 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.749 0 1.442-.239 2.01-.643l.098.169 2.375 2.374c.19.189.543.143.79-.104s.293-.601.104-.791zm-5.377-2.27c-1.221 0-2.213-.991-2.213-2.213 0-1.221.992-2.213 2.213-2.213 1.222 0 2.213.992 2.213 2.213-.001 1.222-.992 2.213-2.213 2.213z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.png
new file mode 100644
index 00000000..df1c61ed
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.svg
new file mode 100644
index 00000000..266349ed
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+ <g id="search">
+ <path id="path3051" d="M10.369 9.474l-2.374-2.375-.169-.099c.403-.566.643-1.26.643-2.009-.001-1.92-1.558-3.477-3.477-3.477-1.921 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.749 0 1.442-.239 2.01-.643l.098.169 2.375 2.374c.19.189.543.143.79-.104s.293-.601.104-.791zm-5.377-2.27c-1.221 0-2.213-.991-2.213-2.213 0-1.221.992-2.213 2.213-2.213 1.222 0 2.213.992 2.213 2.213-.001 1.222-.992 2.213-2.213 2.213z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl-invert.png
new file mode 100644
index 00000000..665a088b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl-invert.svg
new file mode 100644
index 00000000..bd962d93
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12"><style>* { fill: #FFFFFF }</style>
+ <g id="search">
+ <path id="path3051" d="M1.631 9.474l2.374-2.375.169-.099c-.403-.566-.643-1.26-.643-2.009.001-1.92 1.558-3.477 3.477-3.477 1.921 0 3.478 1.557 3.478 3.478 0 1.92-1.557 3.477-3.478 3.477-.749 0-1.442-.239-2.01-.643l-.098.169-2.375 2.374c-.19.189-.543.143-.79-.104s-.293-.601-.104-.791zm5.377-2.27c1.221 0 2.213-.991 2.213-2.213 0-1.221-.992-2.213-2.213-2.213-1.222 0-2.213.992-2.213 2.213.001 1.222.992 2.213 2.213 2.213z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.png
new file mode 100644
index 00000000..c9443d79
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.svg
new file mode 100644
index 00000000..5368fd7c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 12 12">
+ <g id="search">
+ <path id="path3051" d="M1.631 9.474l2.374-2.375.169-.099c-.403-.566-.643-1.26-.643-2.009.001-1.92 1.558-3.477 3.477-3.477 1.921 0 3.478 1.557 3.478 3.478 0 1.92-1.557 3.477-3.478 3.477-.749 0-1.442-.239-2.01-.643l-.098.169-2.375 2.374c-.19.189-.543.143-.79-.104s-.293-.601-.104-.791zm5.377-2.27c1.221 0 2.213-.991 2.213-2.213 0-1.221-.992-2.213-2.213-2.213-1.222 0-2.213.992-2.213 2.213.001 1.222.992 2.213 2.213 2.213z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/images/textures/pending.gif b/resources/lib/oojs-ui/themes/mediawiki/images/textures/pending.gif
index 1194eed2..1194eed2 100644
--- a/resources/lib/oojs-ui/images/textures/pending.gif
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/textures/pending.gif
Binary files differ
diff --git a/resources/lib/oojs-ui/images/textures/transparency.png b/resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.png
index 1843f27d..1843f27d 100644
--- a/resources/lib/oojs-ui/images/textures/transparency.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.png
Binary files differ
diff --git a/resources/lib/oojs-ui/images/textures/transparency.svg b/resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.svg
index 63a0b57c..63a0b57c 100644
--- a/resources/lib/oojs-ui/images/textures/transparency.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.svg
diff --git a/resources/lib/oojs-ui/themes/minerva/images/icons/check.png b/resources/lib/oojs-ui/themes/minerva/images/icons/check.png
deleted file mode 100644
index 65026a0f..00000000
--- a/resources/lib/oojs-ui/themes/minerva/images/icons/check.png
+++ /dev/null
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/minerva/images/icons/check.svg b/resources/lib/oojs-ui/themes/minerva/images/icons/check.svg
deleted file mode 100644
index 6a91939f..00000000
--- a/resources/lib/oojs-ui/themes/minerva/images/icons/check.svg
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 16.0.4, 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" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
- width="44.075px" height="44.076px" viewBox="0 0 44.075 44.076" enable-background="new 0 0 44.075 44.076" xml:space="preserve">
-<polygon fill="#FFFFFF" points="41.673,12.657 15.385,37.159 15.201,36.961 10.037,31.424 2.402,23.239 8.057,17.962 15.693,26.157
- 36.319,6.917 "/>
-</svg>
diff --git a/resources/lib/oojs/oojs.jquery.js b/resources/lib/oojs/oojs.jquery.js
index c62df221..18dc5649 100644
--- a/resources/lib/oojs/oojs.jquery.js
+++ b/resources/lib/oojs/oojs.jquery.js
@@ -1,12 +1,12 @@
/*!
- * OOjs v1.1.1 optimised for jQuery
+ * OOjs v1.1.6 optimised for jQuery
* https://www.mediawiki.org/wiki/OOjs
*
- * Copyright 2011-2014 OOjs Team and other contributors.
+ * Copyright 2011-2015 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2014-09-11T00:40:09Z
+ * Date: 2015-03-19T00:42:55Z
*/
( function ( global ) {
@@ -20,6 +20,7 @@ var
* @singleton
*/
oo = {},
+ // Optimisation: Local reference to Object.prototype.hasOwnProperty
hasOwn = oo.hasOwnProperty,
toString = oo.toString;
@@ -159,6 +160,64 @@ oo.mixinClass = function ( targetFn, originFn ) {
/* Object Methods */
/**
+ * Get a deeply nested property of an object using variadic arguments, protecting against
+ * undefined property errors.
+ *
+ * `quux = oo.getProp( obj, 'foo', 'bar', 'baz' );` is equivalent to `quux = obj.foo.bar.baz;`
+ * except that the former protects against JS errors if one of the intermediate properties
+ * is undefined. Instead of throwing an error, this function will return undefined in
+ * that case.
+ *
+ * @param {Object} obj
+ * @param {Mixed...} [keys]
+ * @return obj[arguments[1]][arguments[2]].... or undefined
+ */
+oo.getProp = function ( obj ) {
+ var i,
+ retval = obj;
+ for ( i = 1; i < arguments.length; i++ ) {
+ if ( retval === undefined || retval === null ) {
+ // Trying to access a property of undefined or null causes an error
+ return undefined;
+ }
+ retval = retval[arguments[i]];
+ }
+ return retval;
+};
+
+/**
+ * Set a deeply nested property of an object using variadic arguments, protecting against
+ * undefined property errors.
+ *
+ * `oo.setProp( obj, 'foo', 'bar', 'baz' );` is equivalent to `obj.foo.bar = baz;` except that
+ * the former protects against JS errors if one of the intermediate properties is
+ * undefined. Instead of throwing an error, undefined intermediate properties will be
+ * initialized to an empty object. If an intermediate property is not an object, or if obj itself
+ * is not an object, this function will silently abort.
+ *
+ * @param {Object} obj
+ * @param {Mixed...} [keys]
+ * @param {Mixed} [value]
+ */
+oo.setProp = function ( obj ) {
+ var i,
+ prop = obj;
+ if ( Object( obj ) !== obj ) {
+ return;
+ }
+ for ( i = 1; i < arguments.length - 2; i++ ) {
+ if ( prop[arguments[i]] === undefined ) {
+ prop[arguments[i]] = {};
+ }
+ if ( Object( prop[arguments[i]] ) !== prop[arguments[i]] ) {
+ return;
+ }
+ prop = prop[arguments[i]];
+ }
+ prop[arguments[arguments.length - 2]] = arguments[arguments.length - 1];
+};
+
+/**
* Create a new object that is an instance of the same
* constructor as the input, inherits from the same object
* and contains the same own properties.
@@ -228,7 +287,8 @@ oo.getObjectValues = function ( obj ) {
*
* @param {Object|undefined|null} a First object to compare
* @param {Object|undefined|null} b Second object to compare
- * @param {boolean} [asymmetrical] Whether to check only that b contains values from a
+ * @param {boolean} [asymmetrical] Whether to check only that a's values are equal to b's
+ * (i.e. a is a subset of b)
* @return {boolean} If the objects contain the same values as each other
*/
oo.compare = function ( a, b, asymmetrical ) {
@@ -241,10 +301,16 @@ oo.compare = function ( a, b, asymmetrical ) {
a = a || {};
b = b || {};
+ if ( typeof a.nodeType === 'number' && typeof a.isEqualNode === 'function' ) {
+ return a.isEqualNode( b );
+ }
+
for ( k in a ) {
- if ( !hasOwn.call( a, k ) ) {
- // Support es3-shim: Without this filter, comparing [] to {} will be false in ES3
+ if ( !hasOwn.call( a, k ) || a[k] === undefined || a[k] === b[k] ) {
+ // Support es3-shim: Without the hasOwn filter, comparing [] to {} will be false in ES3
// because the shimmed "forEach" is enumerable and shows up in Array but not Object.
+ // Also ignore undefined values, because there is no conceptual difference between
+ // a key that is absent and a key that is present but whose value is undefined.
continue;
}
@@ -257,7 +323,7 @@ oo.compare = function ( a, b, asymmetrical ) {
( aType === 'string' || aType === 'number' || aType === 'boolean' ) &&
aValue !== bValue
) ||
- ( aValue === Object( aValue ) && !oo.compare( aValue, bValue, asymmetrical ) ) ) {
+ ( aValue === Object( aValue ) && !oo.compare( aValue, bValue, true ) ) ) {
return false;
}
}
@@ -370,6 +436,21 @@ oo.getHash.keySortReplacer = function ( key, val ) {
};
/**
+ * Get the unique values of an array, removing duplicates
+ *
+ * @param {Array} arr Array
+ * @return {Array} Unique values in array
+ */
+oo.unique = function ( arr ) {
+ return arr.reduce( function ( result, current ) {
+ if ( result.indexOf( current ) === -1 ) {
+ result.push( current );
+ }
+ return result;
+ }, [] );
+};
+
+/**
* Compute the union (duplicate-free merge) of a set of arrays.
*
* Arrays values must be convertable to object keys (strings).
@@ -506,11 +587,6 @@ oo.isPlainObject = $.isPlainObject;
if ( context === undefined || context === null ) {
throw new Error( 'Method name "' + method + '" has no context.' );
}
- if ( !( method in context ) ) {
- // Technically the method does not need to exist yet: it could be
- // added before call time. But this probably signals a typo.
- throw new Error( 'Method not found: "' + method + '"' );
- }
if ( typeof context[method] !== 'function' ) {
// Technically the property could be replaced by a function before
// call time. But this probably signals a typo.
@@ -565,11 +641,11 @@ oo.isPlainObject = $.isPlainObject;
*/
oo.EventEmitter.prototype.once = function ( event, listener ) {
var eventEmitter = this,
- listenerWrapper = function () {
- eventEmitter.off( event, listenerWrapper );
- listener.apply( eventEmitter, Array.prototype.slice.call( arguments, 0 ) );
+ wrapper = function () {
+ eventEmitter.off( event, wrapper );
+ return listener.apply( this, arguments );
};
- return this.on( event, listenerWrapper );
+ return this.on( event, wrapper );
};
/**
@@ -593,7 +669,7 @@ oo.isPlainObject = $.isPlainObject;
validateMethod( method, context );
- if ( !( event in this.bindings ) || !this.bindings[event].length ) {
+ if ( !hasOwn.call( this.bindings, event ) || !this.bindings[event].length ) {
// No matching bindings
return this;
}
@@ -630,12 +706,15 @@ oo.isPlainObject = $.isPlainObject;
* @return {boolean} If event was handled by at least one listener
*/
oo.EventEmitter.prototype.emit = function ( event ) {
- var i, len, binding, bindings, args, method;
+ var args = [],
+ i, len, binding, bindings, method;
- if ( event in this.bindings ) {
+ if ( hasOwn.call( this.bindings, event ) ) {
// Slicing ensures that we don't get tripped up by event handlers that add/remove bindings
bindings = this.bindings[event].slice();
- args = Array.prototype.slice.call( arguments, 1 );
+ for ( i = 1, len = arguments.length; i < len; i++ ) {
+ args.push( arguments[i] );
+ }
for ( i = 0, len = bindings.length; i < len; i++ ) {
binding = bindings[i];
if ( typeof binding.method === 'string' ) {
@@ -849,7 +928,8 @@ oo.Factory.prototype.register = function ( constructor ) {
* @throws {Error} Unknown object name
*/
oo.Factory.prototype.create = function ( name ) {
- var args, obj,
+ var obj, i,
+ args = [],
constructor = this.lookup( name );
if ( !constructor ) {
@@ -857,7 +937,9 @@ oo.Factory.prototype.create = function ( name ) {
}
// Convert arguments to array and shift the first argument (name) off
- args = Array.prototype.slice.call( arguments, 1 );
+ for ( i = 1; i < arguments.length; i++ ) {
+ args.push( arguments[i] );
+ }
// We can't use the "new" operator with .apply directly because apply needs a
// context. So instead just do what "new" does: create an object that inherits from
diff --git a/resources/lib/jquery/jquery.qunit.css b/resources/lib/qunitjs/qunit.css
index 93026e3b..0eb0b017 100644
--- a/resources/lib/jquery/jquery.qunit.css
+++ b/resources/lib/qunitjs/qunit.css
@@ -1,12 +1,12 @@
/*!
- * QUnit 1.14.0
+ * QUnit 1.17.1
* http://qunitjs.com/
*
- * Copyright 2013 jQuery Foundation and other contributors
+ * Copyright jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2014-01-31T16:40Z
+ * Date: 2015-01-20T19:39Z
*/
/** Font Family and Sizes */
@@ -62,14 +62,14 @@
}
#qunit-testrunner-toolbar {
- padding: 0.5em 0 0.5em 2em;
+ padding: 0.5em 1em 0.5em 1em;
color: #5E740B;
background-color: #EEE;
overflow: hidden;
}
#qunit-userAgent {
- padding: 0.5em 0 0.5em 2.5em;
+ padding: 0.5em 1em 0.5em 1em;
background-color: #2B81AF;
color: #FFF;
text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px;
@@ -77,6 +77,18 @@
#qunit-modulefilter-container {
float: right;
+ padding: 0.2em;
+}
+
+.qunit-url-config {
+ display: inline-block;
+ padding: 0.1em;
+}
+
+.qunit-filter {
+ display: block;
+ float: right;
+ margin-left: 1em;
}
/** Tests: Pass/Fail */
@@ -86,12 +98,24 @@
}
#qunit-tests li {
- padding: 0.4em 0.5em 0.4em 2.5em;
+ padding: 0.4em 1em 0.4em 1em;
border-bottom: 1px solid #FFF;
list-style-position: inside;
}
-#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running {
+#qunit-tests > li {
+ display: none;
+}
+
+#qunit-tests li.running,
+#qunit-tests li.pass,
+#qunit-tests li.fail,
+#qunit-tests li.skipped {
+ display: list-item;
+}
+
+#qunit-tests.hidepass li.running,
+#qunit-tests.hidepass li.pass {
display: none;
}
@@ -99,6 +123,10 @@
cursor: pointer;
}
+#qunit-tests li.skipped strong {
+ cursor: default;
+}
+
#qunit-tests li a {
padding: 0.5em;
color: #C2CCD1;
@@ -211,11 +239,26 @@
#qunit-banner.qunit-fail { background-color: #EE5757; }
+/*** Skipped tests */
+
+#qunit-tests .skipped {
+ background-color: #EBECE9;
+}
+
+#qunit-tests .qunit-skipped-label {
+ background-color: #F4FF77;
+ display: inline-block;
+ font-style: normal;
+ color: #366097;
+ line-height: 1.8em;
+ padding: 0 0.5em;
+ margin: -0.4em 0.4em -0.4em 0;
+}
/** Result */
#qunit-testresult {
- padding: 0.5em 0.5em 0.5em 2.5em;
+ padding: 0.5em 1em 0.5em 1em;
color: #2B81AF;
background-color: #D2E0E6;
diff --git a/resources/lib/qunitjs/qunit.js b/resources/lib/qunitjs/qunit.js
new file mode 100644
index 00000000..006ca474
--- /dev/null
+++ b/resources/lib/qunitjs/qunit.js
@@ -0,0 +1,2875 @@
+/*!
+ * QUnit 1.17.1
+ * http://qunitjs.com/
+ *
+ * Copyright jQuery Foundation and other contributors
+ * Released under the MIT license
+ * http://jquery.org/license
+ *
+ * Date: 2015-01-20T19:39Z
+ */
+
+(function( window ) {
+
+var QUnit,
+ config,
+ onErrorFnPrev,
+ loggingCallbacks = {},
+ fileName = ( sourceFromStacktrace( 0 ) || "" ).replace( /(:\d+)+\)?/, "" ).replace( /.+\//, "" ),
+ toString = Object.prototype.toString,
+ hasOwn = Object.prototype.hasOwnProperty,
+ // Keep a local reference to Date (GH-283)
+ Date = window.Date,
+ now = Date.now || function() {
+ return new Date().getTime();
+ },
+ globalStartCalled = false,
+ runStarted = false,
+ setTimeout = window.setTimeout,
+ clearTimeout = window.clearTimeout,
+ defined = {
+ document: window.document !== undefined,
+ setTimeout: window.setTimeout !== undefined,
+ sessionStorage: (function() {
+ var x = "qunit-test-string";
+ try {
+ sessionStorage.setItem( x, x );
+ sessionStorage.removeItem( x );
+ return true;
+ } catch ( e ) {
+ return false;
+ }
+ }())
+ },
+ /**
+ * Provides a normalized error string, correcting an issue
+ * with IE 7 (and prior) where Error.prototype.toString is
+ * not properly implemented
+ *
+ * Based on http://es5.github.com/#x15.11.4.4
+ *
+ * @param {String|Error} error
+ * @return {String} error message
+ */
+ errorString = function( error ) {
+ var name, message,
+ errorString = error.toString();
+ if ( errorString.substring( 0, 7 ) === "[object" ) {
+ name = error.name ? error.name.toString() : "Error";
+ message = error.message ? error.message.toString() : "";
+ if ( name && message ) {
+ return name + ": " + message;
+ } else if ( name ) {
+ return name;
+ } else if ( message ) {
+ return message;
+ } else {
+ return "Error";
+ }
+ } else {
+ return errorString;
+ }
+ },
+ /**
+ * Makes a clone of an object using only Array or Object as base,
+ * and copies over the own enumerable properties.
+ *
+ * @param {Object} obj
+ * @return {Object} New object with only the own properties (recursively).
+ */
+ objectValues = function( obj ) {
+ var key, val,
+ vals = QUnit.is( "array", obj ) ? [] : {};
+ for ( key in obj ) {
+ if ( hasOwn.call( obj, key ) ) {
+ val = obj[ key ];
+ vals[ key ] = val === Object( val ) ? objectValues( val ) : val;
+ }
+ }
+ return vals;
+ };
+
+QUnit = {};
+
+/**
+ * Config object: Maintain internal state
+ * Later exposed as QUnit.config
+ * `config` initialized at top of scope
+ */
+config = {
+ // The queue of tests to run
+ queue: [],
+
+ // block until document ready
+ blocking: true,
+
+ // by default, run previously failed tests first
+ // very useful in combination with "Hide passed tests" checked
+ reorder: true,
+
+ // by default, modify document.title when suite is done
+ altertitle: true,
+
+ // by default, scroll to top of the page when suite is done
+ scrolltop: true,
+
+ // when enabled, all tests must call expect()
+ requireExpects: false,
+
+ // add checkboxes that are persisted in the query-string
+ // when enabled, the id is set to `true` as a `QUnit.config` property
+ urlConfig: [
+ {
+ id: "hidepassed",
+ label: "Hide passed tests",
+ tooltip: "Only show tests and assertions that fail. Stored as query-strings."
+ },
+ {
+ id: "noglobals",
+ label: "Check for Globals",
+ tooltip: "Enabling this will test if any test introduces new properties on the " +
+ "`window` object. Stored as query-strings."
+ },
+ {
+ id: "notrycatch",
+ label: "No try-catch",
+ tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging " +
+ "exceptions in IE reasonable. Stored as query-strings."
+ }
+ ],
+
+ // Set of all modules.
+ modules: [],
+
+ // The first unnamed module
+ currentModule: {
+ name: "",
+ tests: []
+ },
+
+ callbacks: {}
+};
+
+// Push a loose unnamed module to the modules collection
+config.modules.push( config.currentModule );
+
+// Initialize more QUnit.config and QUnit.urlParams
+(function() {
+ var i, current,
+ location = window.location || { search: "", protocol: "file:" },
+ params = location.search.slice( 1 ).split( "&" ),
+ length = params.length,
+ urlParams = {};
+
+ if ( params[ 0 ] ) {
+ for ( i = 0; i < length; i++ ) {
+ current = params[ i ].split( "=" );
+ current[ 0 ] = decodeURIComponent( current[ 0 ] );
+
+ // allow just a key to turn on a flag, e.g., test.html?noglobals
+ current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true;
+ if ( urlParams[ current[ 0 ] ] ) {
+ urlParams[ current[ 0 ] ] = [].concat( urlParams[ current[ 0 ] ], current[ 1 ] );
+ } else {
+ urlParams[ current[ 0 ] ] = current[ 1 ];
+ }
+ }
+ }
+
+ if ( urlParams.filter === true ) {
+ delete urlParams.filter;
+ }
+
+ QUnit.urlParams = urlParams;
+
+ // String search anywhere in moduleName+testName
+ config.filter = urlParams.filter;
+
+ config.testId = [];
+ if ( urlParams.testId ) {
+
+ // Ensure that urlParams.testId is an array
+ urlParams.testId = [].concat( urlParams.testId );
+ for ( i = 0; i < urlParams.testId.length; i++ ) {
+ config.testId.push( urlParams.testId[ i ] );
+ }
+ }
+
+ // Figure out if we're running the tests from a server or not
+ QUnit.isLocal = location.protocol === "file:";
+}());
+
+// Root QUnit object.
+// `QUnit` initialized at top of scope
+extend( QUnit, {
+
+ // call on start of module test to prepend name to all tests
+ module: function( name, testEnvironment ) {
+ var currentModule = {
+ name: name,
+ testEnvironment: testEnvironment,
+ tests: []
+ };
+
+ // DEPRECATED: handles setup/teardown functions,
+ // beforeEach and afterEach should be used instead
+ if ( testEnvironment && testEnvironment.setup ) {
+ testEnvironment.beforeEach = testEnvironment.setup;
+ delete testEnvironment.setup;
+ }
+ if ( testEnvironment && testEnvironment.teardown ) {
+ testEnvironment.afterEach = testEnvironment.teardown;
+ delete testEnvironment.teardown;
+ }
+
+ config.modules.push( currentModule );
+ config.currentModule = currentModule;
+ },
+
+ // DEPRECATED: QUnit.asyncTest() will be removed in QUnit 2.0.
+ asyncTest: function( testName, expected, callback ) {
+ if ( arguments.length === 2 ) {
+ callback = expected;
+ expected = null;
+ }
+
+ QUnit.test( testName, expected, callback, true );
+ },
+
+ test: function( testName, expected, callback, async ) {
+ var test;
+
+ if ( arguments.length === 2 ) {
+ callback = expected;
+ expected = null;
+ }
+
+ test = new Test({
+ testName: testName,
+ expected: expected,
+ async: async,
+ callback: callback
+ });
+
+ test.queue();
+ },
+
+ skip: function( testName ) {
+ var test = new Test({
+ testName: testName,
+ skip: true
+ });
+
+ test.queue();
+ },
+
+ // DEPRECATED: The functionality of QUnit.start() will be altered in QUnit 2.0.
+ // In QUnit 2.0, invoking it will ONLY affect the `QUnit.config.autostart` blocking behavior.
+ start: function( count ) {
+ var globalStartAlreadyCalled = globalStartCalled;
+
+ if ( !config.current ) {
+ globalStartCalled = true;
+
+ if ( runStarted ) {
+ throw new Error( "Called start() outside of a test context while already started" );
+ } else if ( globalStartAlreadyCalled || count > 1 ) {
+ throw new Error( "Called start() outside of a test context too many times" );
+ } else if ( config.autostart ) {
+ throw new Error( "Called start() outside of a test context when " +
+ "QUnit.config.autostart was true" );
+ } else if ( !config.pageLoaded ) {
+
+ // The page isn't completely loaded yet, so bail out and let `QUnit.load` handle it
+ config.autostart = true;
+ return;
+ }
+ } else {
+
+ // If a test is running, adjust its semaphore
+ config.current.semaphore -= count || 1;
+
+ // Don't start until equal number of stop-calls
+ if ( config.current.semaphore > 0 ) {
+ return;
+ }
+
+ // throw an Error if start is called more often than stop
+ if ( config.current.semaphore < 0 ) {
+ config.current.semaphore = 0;
+
+ QUnit.pushFailure(
+ "Called start() while already started (test's semaphore was 0 already)",
+ sourceFromStacktrace( 2 )
+ );
+ return;
+ }
+ }
+
+ resumeProcessing();
+ },
+
+ // DEPRECATED: QUnit.stop() will be removed in QUnit 2.0.
+ stop: function( count ) {
+
+ // If there isn't a test running, don't allow QUnit.stop() to be called
+ if ( !config.current ) {
+ throw new Error( "Called stop() outside of a test context" );
+ }
+
+ // If a test is running, adjust its semaphore
+ config.current.semaphore += count || 1;
+
+ pauseProcessing();
+ },
+
+ config: config,
+
+ // Safe object type checking
+ is: function( type, obj ) {
+ return QUnit.objectType( obj ) === type;
+ },
+
+ objectType: function( obj ) {
+ if ( typeof obj === "undefined" ) {
+ return "undefined";
+ }
+
+ // Consider: typeof null === object
+ if ( obj === null ) {
+ return "null";
+ }
+
+ var match = toString.call( obj ).match( /^\[object\s(.*)\]$/ ),
+ type = match && match[ 1 ] || "";
+
+ switch ( type ) {
+ case "Number":
+ if ( isNaN( obj ) ) {
+ return "nan";
+ }
+ return "number";
+ case "String":
+ case "Boolean":
+ case "Array":
+ case "Date":
+ case "RegExp":
+ case "Function":
+ return type.toLowerCase();
+ }
+ if ( typeof obj === "object" ) {
+ return "object";
+ }
+ return undefined;
+ },
+
+ extend: extend,
+
+ load: function() {
+ config.pageLoaded = true;
+
+ // Initialize the configuration options
+ extend( config, {
+ stats: { all: 0, bad: 0 },
+ moduleStats: { all: 0, bad: 0 },
+ started: 0,
+ updateRate: 1000,
+ autostart: true,
+ filter: ""
+ }, true );
+
+ config.blocking = false;
+
+ if ( config.autostart ) {
+ resumeProcessing();
+ }
+ }
+});
+
+// Register logging callbacks
+(function() {
+ var i, l, key,
+ callbacks = [ "begin", "done", "log", "testStart", "testDone",
+ "moduleStart", "moduleDone" ];
+
+ function registerLoggingCallback( key ) {
+ var loggingCallback = function( callback ) {
+ if ( QUnit.objectType( callback ) !== "function" ) {
+ throw new Error(
+ "QUnit logging methods require a callback function as their first parameters."
+ );
+ }
+
+ config.callbacks[ key ].push( callback );
+ };
+
+ // DEPRECATED: This will be removed on QUnit 2.0.0+
+ // Stores the registered functions allowing restoring
+ // at verifyLoggingCallbacks() if modified
+ loggingCallbacks[ key ] = loggingCallback;
+
+ return loggingCallback;
+ }
+
+ for ( i = 0, l = callbacks.length; i < l; i++ ) {
+ key = callbacks[ i ];
+
+ // Initialize key collection of logging callback
+ if ( QUnit.objectType( config.callbacks[ key ] ) === "undefined" ) {
+ config.callbacks[ key ] = [];
+ }
+
+ QUnit[ key ] = registerLoggingCallback( key );
+ }
+})();
+
+// `onErrorFnPrev` initialized at top of scope
+// Preserve other handlers
+onErrorFnPrev = window.onerror;
+
+// Cover uncaught exceptions
+// Returning true will suppress the default browser handler,
+// returning false will let it run.
+window.onerror = function( error, filePath, linerNr ) {
+ var ret = false;
+ if ( onErrorFnPrev ) {
+ ret = onErrorFnPrev( error, filePath, linerNr );
+ }
+
+ // Treat return value as window.onerror itself does,
+ // Only do our handling if not suppressed.
+ if ( ret !== true ) {
+ if ( QUnit.config.current ) {
+ if ( QUnit.config.current.ignoreGlobalErrors ) {
+ return true;
+ }
+ QUnit.pushFailure( error, filePath + ":" + linerNr );
+ } else {
+ QUnit.test( "global failure", extend(function() {
+ QUnit.pushFailure( error, filePath + ":" + linerNr );
+ }, { validTest: true } ) );
+ }
+ return false;
+ }
+
+ return ret;
+};
+
+function done() {
+ var runtime, passed;
+
+ config.autorun = true;
+
+ // Log the last module results
+ if ( config.previousModule ) {
+ runLoggingCallbacks( "moduleDone", {
+ name: config.previousModule.name,
+ tests: config.previousModule.tests,
+ failed: config.moduleStats.bad,
+ passed: config.moduleStats.all - config.moduleStats.bad,
+ total: config.moduleStats.all,
+ runtime: now() - config.moduleStats.started
+ });
+ }
+ delete config.previousModule;
+
+ runtime = now() - config.started;
+ passed = config.stats.all - config.stats.bad;
+
+ runLoggingCallbacks( "done", {
+ failed: config.stats.bad,
+ passed: passed,
+ total: config.stats.all,
+ runtime: runtime
+ });
+}
+
+// Doesn't support IE6 to IE9
+// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack
+function extractStacktrace( e, offset ) {
+ offset = offset === undefined ? 4 : offset;
+
+ var stack, include, i;
+
+ if ( e.stacktrace ) {
+
+ // Opera 12.x
+ return e.stacktrace.split( "\n" )[ offset + 3 ];
+ } else if ( e.stack ) {
+
+ // Firefox, Chrome, Safari 6+, IE10+, PhantomJS and Node
+ stack = e.stack.split( "\n" );
+ if ( /^error$/i.test( stack[ 0 ] ) ) {
+ stack.shift();
+ }
+ if ( fileName ) {
+ include = [];
+ for ( i = offset; i < stack.length; i++ ) {
+ if ( stack[ i ].indexOf( fileName ) !== -1 ) {
+ break;
+ }
+ include.push( stack[ i ] );
+ }
+ if ( include.length ) {
+ return include.join( "\n" );
+ }
+ }
+ return stack[ offset ];
+ } else if ( e.sourceURL ) {
+
+ // Safari < 6
+ // exclude useless self-reference for generated Error objects
+ if ( /qunit.js$/.test( e.sourceURL ) ) {
+ return;
+ }
+
+ // for actual exceptions, this is useful
+ return e.sourceURL + ":" + e.line;
+ }
+}
+
+function sourceFromStacktrace( offset ) {
+ var e = new Error();
+ if ( !e.stack ) {
+ try {
+ throw e;
+ } catch ( err ) {
+ // This should already be true in most browsers
+ e = err;
+ }
+ }
+ return extractStacktrace( e, offset );
+}
+
+function synchronize( callback, last ) {
+ if ( QUnit.objectType( callback ) === "array" ) {
+ while ( callback.length ) {
+ synchronize( callback.shift() );
+ }
+ return;
+ }
+ config.queue.push( callback );
+
+ if ( config.autorun && !config.blocking ) {
+ process( last );
+ }
+}
+
+function process( last ) {
+ function next() {
+ process( last );
+ }
+ var start = now();
+ config.depth = ( config.depth || 0 ) + 1;
+
+ while ( config.queue.length && !config.blocking ) {
+ if ( !defined.setTimeout || config.updateRate <= 0 ||
+ ( ( now() - start ) < config.updateRate ) ) {
+ if ( config.current ) {
+
+ // Reset async tracking for each phase of the Test lifecycle
+ config.current.usedAsync = false;
+ }
+ config.queue.shift()();
+ } else {
+ setTimeout( next, 13 );
+ break;
+ }
+ }
+ config.depth--;
+ if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) {
+ done();
+ }
+}
+
+function begin() {
+ var i, l,
+ modulesLog = [];
+
+ // If the test run hasn't officially begun yet
+ if ( !config.started ) {
+
+ // Record the time of the test run's beginning
+ config.started = now();
+
+ verifyLoggingCallbacks();
+
+ // Delete the loose unnamed module if unused.
+ if ( config.modules[ 0 ].name === "" && config.modules[ 0 ].tests.length === 0 ) {
+ config.modules.shift();
+ }
+
+ // Avoid unnecessary information by not logging modules' test environments
+ for ( i = 0, l = config.modules.length; i < l; i++ ) {
+ modulesLog.push({
+ name: config.modules[ i ].name,
+ tests: config.modules[ i ].tests
+ });
+ }
+
+ // The test run is officially beginning now
+ runLoggingCallbacks( "begin", {
+ totalTests: Test.count,
+ modules: modulesLog
+ });
+ }
+
+ config.blocking = false;
+ process( true );
+}
+
+function resumeProcessing() {
+ runStarted = true;
+
+ // A slight delay to allow this iteration of the event loop to finish (more assertions, etc.)
+ if ( defined.setTimeout ) {
+ setTimeout(function() {
+ if ( config.current && config.current.semaphore > 0 ) {
+ return;
+ }
+ if ( config.timeout ) {
+ clearTimeout( config.timeout );
+ }
+
+ begin();
+ }, 13 );
+ } else {
+ begin();
+ }
+}
+
+function pauseProcessing() {
+ config.blocking = true;
+
+ if ( config.testTimeout && defined.setTimeout ) {
+ clearTimeout( config.timeout );
+ config.timeout = setTimeout(function() {
+ if ( config.current ) {
+ config.current.semaphore = 0;
+ QUnit.pushFailure( "Test timed out", sourceFromStacktrace( 2 ) );
+ } else {
+ throw new Error( "Test timed out" );
+ }
+ resumeProcessing();
+ }, config.testTimeout );
+ }
+}
+
+function saveGlobal() {
+ config.pollution = [];
+
+ if ( config.noglobals ) {
+ for ( var key in window ) {
+ if ( hasOwn.call( window, key ) ) {
+ // in Opera sometimes DOM element ids show up here, ignore them
+ if ( /^qunit-test-output/.test( key ) ) {
+ continue;
+ }
+ config.pollution.push( key );
+ }
+ }
+ }
+}
+
+function checkPollution() {
+ var newGlobals,
+ deletedGlobals,
+ old = config.pollution;
+
+ saveGlobal();
+
+ newGlobals = diff( config.pollution, old );
+ if ( newGlobals.length > 0 ) {
+ QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join( ", " ) );
+ }
+
+ deletedGlobals = diff( old, config.pollution );
+ if ( deletedGlobals.length > 0 ) {
+ QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join( ", " ) );
+ }
+}
+
+// returns a new Array with the elements that are in a but not in b
+function diff( a, b ) {
+ var i, j,
+ result = a.slice();
+
+ for ( i = 0; i < result.length; i++ ) {
+ for ( j = 0; j < b.length; j++ ) {
+ if ( result[ i ] === b[ j ] ) {
+ result.splice( i, 1 );
+ i--;
+ break;
+ }
+ }
+ }
+ return result;
+}
+
+function extend( a, b, undefOnly ) {
+ for ( var prop in b ) {
+ if ( hasOwn.call( b, prop ) ) {
+
+ // Avoid "Member not found" error in IE8 caused by messing with window.constructor
+ if ( !( prop === "constructor" && a === window ) ) {
+ if ( b[ prop ] === undefined ) {
+ delete a[ prop ];
+ } else if ( !( undefOnly && typeof a[ prop ] !== "undefined" ) ) {
+ a[ prop ] = b[ prop ];
+ }
+ }
+ }
+ }
+
+ return a;
+}
+
+function runLoggingCallbacks( key, args ) {
+ var i, l, callbacks;
+
+ callbacks = config.callbacks[ key ];
+ for ( i = 0, l = callbacks.length; i < l; i++ ) {
+ callbacks[ i ]( args );
+ }
+}
+
+// DEPRECATED: This will be removed on 2.0.0+
+// This function verifies if the loggingCallbacks were modified by the user
+// If so, it will restore it, assign the given callback and print a console warning
+function verifyLoggingCallbacks() {
+ var loggingCallback, userCallback;
+
+ for ( loggingCallback in loggingCallbacks ) {
+ if ( QUnit[ loggingCallback ] !== loggingCallbacks[ loggingCallback ] ) {
+
+ userCallback = QUnit[ loggingCallback ];
+
+ // Restore the callback function
+ QUnit[ loggingCallback ] = loggingCallbacks[ loggingCallback ];
+
+ // Assign the deprecated given callback
+ QUnit[ loggingCallback ]( userCallback );
+
+ if ( window.console && window.console.warn ) {
+ window.console.warn(
+ "QUnit." + loggingCallback + " was replaced with a new value.\n" +
+ "Please, check out the documentation on how to apply logging callbacks.\n" +
+ "Reference: http://api.qunitjs.com/category/callbacks/"
+ );
+ }
+ }
+ }
+}
+
+// from jquery.js
+function inArray( elem, array ) {
+ if ( array.indexOf ) {
+ return array.indexOf( elem );
+ }
+
+ for ( var i = 0, length = array.length; i < length; i++ ) {
+ if ( array[ i ] === elem ) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+function Test( settings ) {
+ var i, l;
+
+ ++Test.count;
+
+ extend( this, settings );
+ this.assertions = [];
+ this.semaphore = 0;
+ this.usedAsync = false;
+ this.module = config.currentModule;
+ this.stack = sourceFromStacktrace( 3 );
+
+ // Register unique strings
+ for ( i = 0, l = this.module.tests; i < l.length; i++ ) {
+ if ( this.module.tests[ i ].name === this.testName ) {
+ this.testName += " ";
+ }
+ }
+
+ this.testId = generateHash( this.module.name, this.testName );
+
+ this.module.tests.push({
+ name: this.testName,
+ testId: this.testId
+ });
+
+ if ( settings.skip ) {
+
+ // Skipped tests will fully ignore any sent callback
+ this.callback = function() {};
+ this.async = false;
+ this.expected = 0;
+ } else {
+ this.assert = new Assert( this );
+ }
+}
+
+Test.count = 0;
+
+Test.prototype = {
+ before: function() {
+ if (
+
+ // Emit moduleStart when we're switching from one module to another
+ this.module !== config.previousModule ||
+
+ // They could be equal (both undefined) but if the previousModule property doesn't
+ // yet exist it means this is the first test in a suite that isn't wrapped in a
+ // module, in which case we'll just emit a moduleStart event for 'undefined'.
+ // Without this, reporters can get testStart before moduleStart which is a problem.
+ !hasOwn.call( config, "previousModule" )
+ ) {
+ if ( hasOwn.call( config, "previousModule" ) ) {
+ runLoggingCallbacks( "moduleDone", {
+ name: config.previousModule.name,
+ tests: config.previousModule.tests,
+ failed: config.moduleStats.bad,
+ passed: config.moduleStats.all - config.moduleStats.bad,
+ total: config.moduleStats.all,
+ runtime: now() - config.moduleStats.started
+ });
+ }
+ config.previousModule = this.module;
+ config.moduleStats = { all: 0, bad: 0, started: now() };
+ runLoggingCallbacks( "moduleStart", {
+ name: this.module.name,
+ tests: this.module.tests
+ });
+ }
+
+ config.current = this;
+
+ this.testEnvironment = extend( {}, this.module.testEnvironment );
+ delete this.testEnvironment.beforeEach;
+ delete this.testEnvironment.afterEach;
+
+ this.started = now();
+ runLoggingCallbacks( "testStart", {
+ name: this.testName,
+ module: this.module.name,
+ testId: this.testId
+ });
+
+ if ( !config.pollution ) {
+ saveGlobal();
+ }
+ },
+
+ run: function() {
+ var promise;
+
+ config.current = this;
+
+ if ( this.async ) {
+ QUnit.stop();
+ }
+
+ this.callbackStarted = now();
+
+ if ( config.notrycatch ) {
+ promise = this.callback.call( this.testEnvironment, this.assert );
+ this.resolvePromise( promise );
+ return;
+ }
+
+ try {
+ promise = this.callback.call( this.testEnvironment, this.assert );
+ this.resolvePromise( promise );
+ } catch ( e ) {
+ this.pushFailure( "Died on test #" + ( this.assertions.length + 1 ) + " " +
+ this.stack + ": " + ( e.message || e ), extractStacktrace( e, 0 ) );
+
+ // else next test will carry the responsibility
+ saveGlobal();
+
+ // Restart the tests if they're blocking
+ if ( config.blocking ) {
+ QUnit.start();
+ }
+ }
+ },
+
+ after: function() {
+ checkPollution();
+ },
+
+ queueHook: function( hook, hookName ) {
+ var promise,
+ test = this;
+ return function runHook() {
+ config.current = test;
+ if ( config.notrycatch ) {
+ promise = hook.call( test.testEnvironment, test.assert );
+ test.resolvePromise( promise, hookName );
+ return;
+ }
+ try {
+ promise = hook.call( test.testEnvironment, test.assert );
+ test.resolvePromise( promise, hookName );
+ } catch ( error ) {
+ test.pushFailure( hookName + " failed on " + test.testName + ": " +
+ ( error.message || error ), extractStacktrace( error, 0 ) );
+ }
+ };
+ },
+
+ // Currently only used for module level hooks, can be used to add global level ones
+ hooks: function( handler ) {
+ var hooks = [];
+
+ // Hooks are ignored on skipped tests
+ if ( this.skip ) {
+ return hooks;
+ }
+
+ if ( this.module.testEnvironment &&
+ QUnit.objectType( this.module.testEnvironment[ handler ] ) === "function" ) {
+ hooks.push( this.queueHook( this.module.testEnvironment[ handler ], handler ) );
+ }
+
+ return hooks;
+ },
+
+ finish: function() {
+ config.current = this;
+ if ( config.requireExpects && this.expected === null ) {
+ this.pushFailure( "Expected number of assertions to be defined, but expect() was " +
+ "not called.", this.stack );
+ } else if ( this.expected !== null && this.expected !== this.assertions.length ) {
+ this.pushFailure( "Expected " + this.expected + " assertions, but " +
+ this.assertions.length + " were run", this.stack );
+ } else if ( this.expected === null && !this.assertions.length ) {
+ this.pushFailure( "Expected at least one assertion, but none were run - call " +
+ "expect(0) to accept zero assertions.", this.stack );
+ }
+
+ var i,
+ bad = 0;
+
+ this.runtime = now() - this.started;
+ config.stats.all += this.assertions.length;
+ config.moduleStats.all += this.assertions.length;
+
+ for ( i = 0; i < this.assertions.length; i++ ) {
+ if ( !this.assertions[ i ].result ) {
+ bad++;
+ config.stats.bad++;
+ config.moduleStats.bad++;
+ }
+ }
+
+ runLoggingCallbacks( "testDone", {
+ name: this.testName,
+ module: this.module.name,
+ skipped: !!this.skip,
+ failed: bad,
+ passed: this.assertions.length - bad,
+ total: this.assertions.length,
+ runtime: this.runtime,
+
+ // HTML Reporter use
+ assertions: this.assertions,
+ testId: this.testId,
+
+ // DEPRECATED: this property will be removed in 2.0.0, use runtime instead
+ duration: this.runtime
+ });
+
+ // QUnit.reset() is deprecated and will be replaced for a new
+ // fixture reset function on QUnit 2.0/2.1.
+ // It's still called here for backwards compatibility handling
+ QUnit.reset();
+
+ config.current = undefined;
+ },
+
+ queue: function() {
+ var bad,
+ test = this;
+
+ if ( !this.valid() ) {
+ return;
+ }
+
+ function run() {
+
+ // each of these can by async
+ synchronize([
+ function() {
+ test.before();
+ },
+
+ test.hooks( "beforeEach" ),
+
+ function() {
+ test.run();
+ },
+
+ test.hooks( "afterEach" ).reverse(),
+
+ function() {
+ test.after();
+ },
+ function() {
+ test.finish();
+ }
+ ]);
+ }
+
+ // `bad` initialized at top of scope
+ // defer when previous test run passed, if storage is available
+ bad = QUnit.config.reorder && defined.sessionStorage &&
+ +sessionStorage.getItem( "qunit-test-" + this.module.name + "-" + this.testName );
+
+ if ( bad ) {
+ run();
+ } else {
+ synchronize( run, true );
+ }
+ },
+
+ push: function( result, actual, expected, message ) {
+ var source,
+ details = {
+ module: this.module.name,
+ name: this.testName,
+ result: result,
+ message: message,
+ actual: actual,
+ expected: expected,
+ testId: this.testId,
+ runtime: now() - this.started
+ };
+
+ if ( !result ) {
+ source = sourceFromStacktrace();
+
+ if ( source ) {
+ details.source = source;
+ }
+ }
+
+ runLoggingCallbacks( "log", details );
+
+ this.assertions.push({
+ result: !!result,
+ message: message
+ });
+ },
+
+ pushFailure: function( message, source, actual ) {
+ if ( !this instanceof Test ) {
+ throw new Error( "pushFailure() assertion outside test context, was " +
+ sourceFromStacktrace( 2 ) );
+ }
+
+ var details = {
+ module: this.module.name,
+ name: this.testName,
+ result: false,
+ message: message || "error",
+ actual: actual || null,
+ testId: this.testId,
+ runtime: now() - this.started
+ };
+
+ if ( source ) {
+ details.source = source;
+ }
+
+ runLoggingCallbacks( "log", details );
+
+ this.assertions.push({
+ result: false,
+ message: message
+ });
+ },
+
+ resolvePromise: function( promise, phase ) {
+ var then, message,
+ test = this;
+ if ( promise != null ) {
+ then = promise.then;
+ if ( QUnit.objectType( then ) === "function" ) {
+ QUnit.stop();
+ then.call(
+ promise,
+ QUnit.start,
+ function( error ) {
+ message = "Promise rejected " +
+ ( !phase ? "during" : phase.replace( /Each$/, "" ) ) +
+ " " + test.testName + ": " + ( error.message || error );
+ test.pushFailure( message, extractStacktrace( error, 0 ) );
+
+ // else next test will carry the responsibility
+ saveGlobal();
+
+ // Unblock
+ QUnit.start();
+ }
+ );
+ }
+ }
+ },
+
+ valid: function() {
+ var include,
+ filter = config.filter,
+ module = QUnit.urlParams.module && QUnit.urlParams.module.toLowerCase(),
+ fullName = ( this.module.name + ": " + this.testName ).toLowerCase();
+
+ // Internally-generated tests are always valid
+ if ( this.callback && this.callback.validTest ) {
+ return true;
+ }
+
+ if ( config.testId.length > 0 && inArray( this.testId, config.testId ) < 0 ) {
+ return false;
+ }
+
+ if ( module && ( !this.module.name || this.module.name.toLowerCase() !== module ) ) {
+ return false;
+ }
+
+ if ( !filter ) {
+ return true;
+ }
+
+ include = filter.charAt( 0 ) !== "!";
+ if ( !include ) {
+ filter = filter.toLowerCase().slice( 1 );
+ }
+
+ // If the filter matches, we need to honour include
+ if ( fullName.indexOf( filter ) !== -1 ) {
+ return include;
+ }
+
+ // Otherwise, do the opposite
+ return !include;
+ }
+
+};
+
+// Resets the test setup. Useful for tests that modify the DOM.
+/*
+DEPRECATED: Use multiple tests instead of resetting inside a test.
+Use testStart or testDone for custom cleanup.
+This method will throw an error in 2.0, and will be removed in 2.1
+*/
+QUnit.reset = function() {
+
+ // Return on non-browser environments
+ // This is necessary to not break on node tests
+ if ( typeof window === "undefined" ) {
+ return;
+ }
+
+ var fixture = defined.document && document.getElementById &&
+ document.getElementById( "qunit-fixture" );
+
+ if ( fixture ) {
+ fixture.innerHTML = config.fixture;
+ }
+};
+
+QUnit.pushFailure = function() {
+ if ( !QUnit.config.current ) {
+ throw new Error( "pushFailure() assertion outside test context, in " +
+ sourceFromStacktrace( 2 ) );
+ }
+
+ // Gets current test obj
+ var currentTest = QUnit.config.current;
+
+ return currentTest.pushFailure.apply( currentTest, arguments );
+};
+
+// Based on Java's String.hashCode, a simple but not
+// rigorously collision resistant hashing function
+function generateHash( module, testName ) {
+ var hex,
+ i = 0,
+ hash = 0,
+ str = module + "\x1C" + testName,
+ len = str.length;
+
+ for ( ; i < len; i++ ) {
+ hash = ( ( hash << 5 ) - hash ) + str.charCodeAt( i );
+ hash |= 0;
+ }
+
+ // Convert the possibly negative integer hash code into an 8 character hex string, which isn't
+ // strictly necessary but increases user understanding that the id is a SHA-like hash
+ hex = ( 0x100000000 + hash ).toString( 16 );
+ if ( hex.length < 8 ) {
+ hex = "0000000" + hex;
+ }
+
+ return hex.slice( -8 );
+}
+
+function Assert( testContext ) {
+ this.test = testContext;
+}
+
+// Assert helpers
+QUnit.assert = Assert.prototype = {
+
+ // Specify the number of expected assertions to guarantee that failed test
+ // (no assertions are run at all) don't slip through.
+ expect: function( asserts ) {
+ if ( arguments.length === 1 ) {
+ this.test.expected = asserts;
+ } else {
+ return this.test.expected;
+ }
+ },
+
+ // Increment this Test's semaphore counter, then return a single-use function that
+ // decrements that counter a maximum of once.
+ async: function() {
+ var test = this.test,
+ popped = false;
+
+ test.semaphore += 1;
+ test.usedAsync = true;
+ pauseProcessing();
+
+ return function done() {
+ if ( !popped ) {
+ test.semaphore -= 1;
+ popped = true;
+ resumeProcessing();
+ } else {
+ test.pushFailure( "Called the callback returned from `assert.async` more than once",
+ sourceFromStacktrace( 2 ) );
+ }
+ };
+ },
+
+ // Exports test.push() to the user API
+ push: function( /* result, actual, expected, message */ ) {
+ var assert = this,
+ currentTest = ( assert instanceof Assert && assert.test ) || QUnit.config.current;
+
+ // Backwards compatibility fix.
+ // Allows the direct use of global exported assertions and QUnit.assert.*
+ // Although, it's use is not recommended as it can leak assertions
+ // to other tests from async tests, because we only get a reference to the current test,
+ // not exactly the test where assertion were intended to be called.
+ if ( !currentTest ) {
+ throw new Error( "assertion outside test context, in " + sourceFromStacktrace( 2 ) );
+ }
+
+ if ( currentTest.usedAsync === true && currentTest.semaphore === 0 ) {
+ currentTest.pushFailure( "Assertion after the final `assert.async` was resolved",
+ sourceFromStacktrace( 2 ) );
+
+ // Allow this assertion to continue running anyway...
+ }
+
+ if ( !( assert instanceof Assert ) ) {
+ assert = currentTest.assert;
+ }
+ return assert.test.push.apply( assert.test, arguments );
+ },
+
+ /**
+ * Asserts rough true-ish result.
+ * @name ok
+ * @function
+ * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" );
+ */
+ ok: function( result, message ) {
+ message = message || ( result ? "okay" : "failed, expected argument to be truthy, was: " +
+ QUnit.dump.parse( result ) );
+ this.push( !!result, result, true, message );
+ },
+
+ /**
+ * Assert that the first two arguments are equal, with an optional message.
+ * Prints out both actual and expected values.
+ * @name equal
+ * @function
+ * @example equal( format( "{0} bytes.", 2), "2 bytes.", "replaces {0} with next argument" );
+ */
+ equal: function( actual, expected, message ) {
+ /*jshint eqeqeq:false */
+ this.push( expected == actual, actual, expected, message );
+ },
+
+ /**
+ * @name notEqual
+ * @function
+ */
+ notEqual: function( actual, expected, message ) {
+ /*jshint eqeqeq:false */
+ this.push( expected != actual, actual, expected, message );
+ },
+
+ /**
+ * @name propEqual
+ * @function
+ */
+ propEqual: function( actual, expected, message ) {
+ actual = objectValues( actual );
+ expected = objectValues( expected );
+ this.push( QUnit.equiv( actual, expected ), actual, expected, message );
+ },
+
+ /**
+ * @name notPropEqual
+ * @function
+ */
+ notPropEqual: function( actual, expected, message ) {
+ actual = objectValues( actual );
+ expected = objectValues( expected );
+ this.push( !QUnit.equiv( actual, expected ), actual, expected, message );
+ },
+
+ /**
+ * @name deepEqual
+ * @function
+ */
+ deepEqual: function( actual, expected, message ) {
+ this.push( QUnit.equiv( actual, expected ), actual, expected, message );
+ },
+
+ /**
+ * @name notDeepEqual
+ * @function
+ */
+ notDeepEqual: function( actual, expected, message ) {
+ this.push( !QUnit.equiv( actual, expected ), actual, expected, message );
+ },
+
+ /**
+ * @name strictEqual
+ * @function
+ */
+ strictEqual: function( actual, expected, message ) {
+ this.push( expected === actual, actual, expected, message );
+ },
+
+ /**
+ * @name notStrictEqual
+ * @function
+ */
+ notStrictEqual: function( actual, expected, message ) {
+ this.push( expected !== actual, actual, expected, message );
+ },
+
+ "throws": function( block, expected, message ) {
+ var actual, expectedType,
+ expectedOutput = expected,
+ ok = false;
+
+ // 'expected' is optional unless doing string comparison
+ if ( message == null && typeof expected === "string" ) {
+ message = expected;
+ expected = null;
+ }
+
+ this.test.ignoreGlobalErrors = true;
+ try {
+ block.call( this.test.testEnvironment );
+ } catch (e) {
+ actual = e;
+ }
+ this.test.ignoreGlobalErrors = false;
+
+ if ( actual ) {
+ expectedType = QUnit.objectType( expected );
+
+ // we don't want to validate thrown error
+ if ( !expected ) {
+ ok = true;
+ expectedOutput = null;
+
+ // expected is a regexp
+ } else if ( expectedType === "regexp" ) {
+ ok = expected.test( errorString( actual ) );
+
+ // expected is a string
+ } else if ( expectedType === "string" ) {
+ ok = expected === errorString( actual );
+
+ // expected is a constructor, maybe an Error constructor
+ } else if ( expectedType === "function" && actual instanceof expected ) {
+ ok = true;
+
+ // expected is an Error object
+ } else if ( expectedType === "object" ) {
+ ok = actual instanceof expected.constructor &&
+ actual.name === expected.name &&
+ actual.message === expected.message;
+
+ // expected is a validation function which returns true if validation passed
+ } else if ( expectedType === "function" && expected.call( {}, actual ) === true ) {
+ expectedOutput = null;
+ ok = true;
+ }
+
+ this.push( ok, actual, expectedOutput, message );
+ } else {
+ this.test.pushFailure( message, null, "No exception was thrown." );
+ }
+ }
+};
+
+// Provide an alternative to assert.throws(), for enviroments that consider throws a reserved word
+// Known to us are: Closure Compiler, Narwhal
+(function() {
+ /*jshint sub:true */
+ Assert.prototype.raises = Assert.prototype[ "throws" ];
+}());
+
+// Test for equality any JavaScript type.
+// Author: Philippe Rathé <prathe@gmail.com>
+QUnit.equiv = (function() {
+
+ // Call the o related callback with the given arguments.
+ function bindCallbacks( o, callbacks, args ) {
+ var prop = QUnit.objectType( o );
+ if ( prop ) {
+ if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) {
+ return callbacks[ prop ].apply( callbacks, args );
+ } else {
+ return callbacks[ prop ]; // or undefined
+ }
+ }
+ }
+
+ // the real equiv function
+ var innerEquiv,
+
+ // stack to decide between skip/abort functions
+ callers = [],
+
+ // stack to avoiding loops from circular referencing
+ parents = [],
+ parentsB = [],
+
+ getProto = Object.getPrototypeOf || function( obj ) {
+ /* jshint camelcase: false, proto: true */
+ return obj.__proto__;
+ },
+ callbacks = (function() {
+
+ // for string, boolean, number and null
+ function useStrictEquality( b, a ) {
+
+ /*jshint eqeqeq:false */
+ if ( b instanceof a.constructor || a instanceof b.constructor ) {
+
+ // to catch short annotation VS 'new' annotation of a
+ // declaration
+ // e.g. var i = 1;
+ // var j = new Number(1);
+ return a == b;
+ } else {
+ return a === b;
+ }
+ }
+
+ return {
+ "string": useStrictEquality,
+ "boolean": useStrictEquality,
+ "number": useStrictEquality,
+ "null": useStrictEquality,
+ "undefined": useStrictEquality,
+
+ "nan": function( b ) {
+ return isNaN( b );
+ },
+
+ "date": function( b, a ) {
+ return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf();
+ },
+
+ "regexp": function( b, a ) {
+ return QUnit.objectType( b ) === "regexp" &&
+
+ // the regex itself
+ a.source === b.source &&
+
+ // and its modifiers
+ a.global === b.global &&
+
+ // (gmi) ...
+ a.ignoreCase === b.ignoreCase &&
+ a.multiline === b.multiline &&
+ a.sticky === b.sticky;
+ },
+
+ // - skip when the property is a method of an instance (OOP)
+ // - abort otherwise,
+ // initial === would have catch identical references anyway
+ "function": function() {
+ var caller = callers[ callers.length - 1 ];
+ return caller !== Object && typeof caller !== "undefined";
+ },
+
+ "array": function( b, a ) {
+ var i, j, len, loop, aCircular, bCircular;
+
+ // b could be an object literal here
+ if ( QUnit.objectType( b ) !== "array" ) {
+ return false;
+ }
+
+ len = a.length;
+ if ( len !== b.length ) {
+ // safe and faster
+ return false;
+ }
+
+ // track reference to avoid circular references
+ parents.push( a );
+ parentsB.push( b );
+ for ( i = 0; i < len; i++ ) {
+ loop = false;
+ for ( j = 0; j < parents.length; j++ ) {
+ aCircular = parents[ j ] === a[ i ];
+ bCircular = parentsB[ j ] === b[ i ];
+ if ( aCircular || bCircular ) {
+ if ( a[ i ] === b[ i ] || aCircular && bCircular ) {
+ loop = true;
+ } else {
+ parents.pop();
+ parentsB.pop();
+ return false;
+ }
+ }
+ }
+ if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) {
+ parents.pop();
+ parentsB.pop();
+ return false;
+ }
+ }
+ parents.pop();
+ parentsB.pop();
+ return true;
+ },
+
+ "object": function( b, a ) {
+
+ /*jshint forin:false */
+ var i, j, loop, aCircular, bCircular,
+ // Default to true
+ eq = true,
+ aProperties = [],
+ bProperties = [];
+
+ // comparing constructors is more strict than using
+ // instanceof
+ if ( a.constructor !== b.constructor ) {
+
+ // Allow objects with no prototype to be equivalent to
+ // objects with Object as their constructor.
+ if ( !( ( getProto( a ) === null && getProto( b ) === Object.prototype ) ||
+ ( getProto( b ) === null && getProto( a ) === Object.prototype ) ) ) {
+ return false;
+ }
+ }
+
+ // stack constructor before traversing properties
+ callers.push( a.constructor );
+
+ // track reference to avoid circular references
+ parents.push( a );
+ parentsB.push( b );
+
+ // be strict: don't ensure hasOwnProperty and go deep
+ for ( i in a ) {
+ loop = false;
+ for ( j = 0; j < parents.length; j++ ) {
+ aCircular = parents[ j ] === a[ i ];
+ bCircular = parentsB[ j ] === b[ i ];
+ if ( aCircular || bCircular ) {
+ if ( a[ i ] === b[ i ] || aCircular && bCircular ) {
+ loop = true;
+ } else {
+ eq = false;
+ break;
+ }
+ }
+ }
+ aProperties.push( i );
+ if ( !loop && !innerEquiv( a[ i ], b[ i ] ) ) {
+ eq = false;
+ break;
+ }
+ }
+
+ parents.pop();
+ parentsB.pop();
+ callers.pop(); // unstack, we are done
+
+ for ( i in b ) {
+ bProperties.push( i ); // collect b's properties
+ }
+
+ // Ensures identical properties name
+ return eq && innerEquiv( aProperties.sort(), bProperties.sort() );
+ }
+ };
+ }());
+
+ innerEquiv = function() { // can take multiple arguments
+ var args = [].slice.apply( arguments );
+ if ( args.length < 2 ) {
+ return true; // end transition
+ }
+
+ return ( (function( a, b ) {
+ if ( a === b ) {
+ return true; // catch the most you can
+ } else if ( a === null || b === null || typeof a === "undefined" ||
+ typeof b === "undefined" ||
+ QUnit.objectType( a ) !== QUnit.objectType( b ) ) {
+
+ // don't lose time with error prone cases
+ return false;
+ } else {
+ return bindCallbacks( a, callbacks, [ b, a ] );
+ }
+
+ // apply transition with (1..n) arguments
+ }( args[ 0 ], args[ 1 ] ) ) &&
+ innerEquiv.apply( this, args.splice( 1, args.length - 1 ) ) );
+ };
+
+ return innerEquiv;
+}());
+
+// Based on jsDump by Ariel Flesler
+// http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html
+QUnit.dump = (function() {
+ function quote( str ) {
+ return "\"" + str.toString().replace( /"/g, "\\\"" ) + "\"";
+ }
+ function literal( o ) {
+ return o + "";
+ }
+ function join( pre, arr, post ) {
+ var s = dump.separator(),
+ base = dump.indent(),
+ inner = dump.indent( 1 );
+ if ( arr.join ) {
+ arr = arr.join( "," + s + inner );
+ }
+ if ( !arr ) {
+ return pre + post;
+ }
+ return [ pre, inner + arr, base + post ].join( s );
+ }
+ function array( arr, stack ) {
+ var i = arr.length,
+ ret = new Array( i );
+
+ if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
+ return "[object Array]";
+ }
+
+ this.up();
+ while ( i-- ) {
+ ret[ i ] = this.parse( arr[ i ], undefined, stack );
+ }
+ this.down();
+ return join( "[", ret, "]" );
+ }
+
+ var reName = /^function (\w+)/,
+ dump = {
+
+ // objType is used mostly internally, you can fix a (custom) type in advance
+ parse: function( obj, objType, stack ) {
+ stack = stack || [];
+ var res, parser, parserType,
+ inStack = inArray( obj, stack );
+
+ if ( inStack !== -1 ) {
+ return "recursion(" + ( inStack - stack.length ) + ")";
+ }
+
+ objType = objType || this.typeOf( obj );
+ parser = this.parsers[ objType ];
+ parserType = typeof parser;
+
+ if ( parserType === "function" ) {
+ stack.push( obj );
+ res = parser.call( this, obj, stack );
+ stack.pop();
+ return res;
+ }
+ return ( parserType === "string" ) ? parser : this.parsers.error;
+ },
+ typeOf: function( obj ) {
+ var type;
+ if ( obj === null ) {
+ type = "null";
+ } else if ( typeof obj === "undefined" ) {
+ type = "undefined";
+ } else if ( QUnit.is( "regexp", obj ) ) {
+ type = "regexp";
+ } else if ( QUnit.is( "date", obj ) ) {
+ type = "date";
+ } else if ( QUnit.is( "function", obj ) ) {
+ type = "function";
+ } else if ( obj.setInterval !== undefined &&
+ obj.document !== undefined &&
+ obj.nodeType === undefined ) {
+ type = "window";
+ } else if ( obj.nodeType === 9 ) {
+ type = "document";
+ } else if ( obj.nodeType ) {
+ type = "node";
+ } else if (
+
+ // native arrays
+ toString.call( obj ) === "[object Array]" ||
+
+ // NodeList objects
+ ( typeof obj.length === "number" && obj.item !== undefined &&
+ ( obj.length ? obj.item( 0 ) === obj[ 0 ] : ( obj.item( 0 ) === null &&
+ obj[ 0 ] === undefined ) ) )
+ ) {
+ type = "array";
+ } else if ( obj.constructor === Error.prototype.constructor ) {
+ type = "error";
+ } else {
+ type = typeof obj;
+ }
+ return type;
+ },
+ separator: function() {
+ return this.multiline ? this.HTML ? "<br />" : "\n" : this.HTML ? "&#160;" : " ";
+ },
+ // extra can be a number, shortcut for increasing-calling-decreasing
+ indent: function( extra ) {
+ if ( !this.multiline ) {
+ return "";
+ }
+ var chr = this.indentChar;
+ if ( this.HTML ) {
+ chr = chr.replace( /\t/g, " " ).replace( / /g, "&#160;" );
+ }
+ return new Array( this.depth + ( extra || 0 ) ).join( chr );
+ },
+ up: function( a ) {
+ this.depth += a || 1;
+ },
+ down: function( a ) {
+ this.depth -= a || 1;
+ },
+ setParser: function( name, parser ) {
+ this.parsers[ name ] = parser;
+ },
+ // The next 3 are exposed so you can use them
+ quote: quote,
+ literal: literal,
+ join: join,
+ //
+ depth: 1,
+ maxDepth: 5,
+
+ // This is the list of parsers, to modify them, use dump.setParser
+ parsers: {
+ window: "[Window]",
+ document: "[Document]",
+ error: function( error ) {
+ return "Error(\"" + error.message + "\")";
+ },
+ unknown: "[Unknown]",
+ "null": "null",
+ "undefined": "undefined",
+ "function": function( fn ) {
+ var ret = "function",
+
+ // functions never have name in IE
+ name = "name" in fn ? fn.name : ( reName.exec( fn ) || [] )[ 1 ];
+
+ if ( name ) {
+ ret += " " + name;
+ }
+ ret += "( ";
+
+ ret = [ ret, dump.parse( fn, "functionArgs" ), "){" ].join( "" );
+ return join( ret, dump.parse( fn, "functionCode" ), "}" );
+ },
+ array: array,
+ nodelist: array,
+ "arguments": array,
+ object: function( map, stack ) {
+ var keys, key, val, i, nonEnumerableProperties,
+ ret = [];
+
+ if ( dump.maxDepth && dump.depth > dump.maxDepth ) {
+ return "[object Object]";
+ }
+
+ dump.up();
+ keys = [];
+ for ( key in map ) {
+ keys.push( key );
+ }
+
+ // Some properties are not always enumerable on Error objects.
+ nonEnumerableProperties = [ "message", "name" ];
+ for ( i in nonEnumerableProperties ) {
+ key = nonEnumerableProperties[ i ];
+ if ( key in map && !( key in keys ) ) {
+ keys.push( key );
+ }
+ }
+ keys.sort();
+ for ( i = 0; i < keys.length; i++ ) {
+ key = keys[ i ];
+ val = map[ key ];
+ ret.push( dump.parse( key, "key" ) + ": " +
+ dump.parse( val, undefined, stack ) );
+ }
+ dump.down();
+ return join( "{", ret, "}" );
+ },
+ node: function( node ) {
+ var len, i, val,
+ open = dump.HTML ? "&lt;" : "<",
+ close = dump.HTML ? "&gt;" : ">",
+ tag = node.nodeName.toLowerCase(),
+ ret = open + tag,
+ attrs = node.attributes;
+
+ if ( attrs ) {
+ for ( i = 0, len = attrs.length; i < len; i++ ) {
+ val = attrs[ i ].nodeValue;
+
+ // IE6 includes all attributes in .attributes, even ones not explicitly
+ // set. Those have values like undefined, null, 0, false, "" or
+ // "inherit".
+ if ( val && val !== "inherit" ) {
+ ret += " " + attrs[ i ].nodeName + "=" +
+ dump.parse( val, "attribute" );
+ }
+ }
+ }
+ ret += close;
+
+ // Show content of TextNode or CDATASection
+ if ( node.nodeType === 3 || node.nodeType === 4 ) {
+ ret += node.nodeValue;
+ }
+
+ return ret + open + "/" + tag + close;
+ },
+
+ // function calls it internally, it's the arguments part of the function
+ functionArgs: function( fn ) {
+ var args,
+ l = fn.length;
+
+ if ( !l ) {
+ return "";
+ }
+
+ args = new Array( l );
+ while ( l-- ) {
+
+ // 97 is 'a'
+ args[ l ] = String.fromCharCode( 97 + l );
+ }
+ return " " + args.join( ", " ) + " ";
+ },
+ // object calls it internally, the key part of an item in a map
+ key: quote,
+ // function calls it internally, it's the content of the function
+ functionCode: "[code]",
+ // node calls it internally, it's an html attribute value
+ attribute: quote,
+ string: quote,
+ date: quote,
+ regexp: literal,
+ number: literal,
+ "boolean": literal
+ },
+ // if true, entities are escaped ( <, >, \t, space and \n )
+ HTML: false,
+ // indentation unit
+ indentChar: " ",
+ // if true, items in a collection, are separated by a \n, else just a space.
+ multiline: true
+ };
+
+ return dump;
+}());
+
+// back compat
+QUnit.jsDump = QUnit.dump;
+
+// For browser, export only select globals
+if ( typeof window !== "undefined" ) {
+
+ // Deprecated
+ // Extend assert methods to QUnit and Global scope through Backwards compatibility
+ (function() {
+ var i,
+ assertions = Assert.prototype;
+
+ function applyCurrent( current ) {
+ return function() {
+ var assert = new Assert( QUnit.config.current );
+ current.apply( assert, arguments );
+ };
+ }
+
+ for ( i in assertions ) {
+ QUnit[ i ] = applyCurrent( assertions[ i ] );
+ }
+ })();
+
+ (function() {
+ var i, l,
+ keys = [
+ "test",
+ "module",
+ "expect",
+ "asyncTest",
+ "start",
+ "stop",
+ "ok",
+ "equal",
+ "notEqual",
+ "propEqual",
+ "notPropEqual",
+ "deepEqual",
+ "notDeepEqual",
+ "strictEqual",
+ "notStrictEqual",
+ "throws"
+ ];
+
+ for ( i = 0, l = keys.length; i < l; i++ ) {
+ window[ keys[ i ] ] = QUnit[ keys[ i ] ];
+ }
+ })();
+
+ window.QUnit = QUnit;
+}
+
+// For nodejs
+if ( typeof module !== "undefined" && module && module.exports ) {
+ module.exports = QUnit;
+
+ // For consistency with CommonJS environments' exports
+ module.exports.QUnit = QUnit;
+}
+
+// For CommonJS with exports, but without module.exports, like Rhino
+if ( typeof exports !== "undefined" && exports ) {
+ exports.QUnit = QUnit;
+}
+
+// Get a reference to the global object, like window in browsers
+}( (function() {
+ return this;
+})() ));
+
+/*istanbul ignore next */
+// jscs:disable maximumLineLength
+/*
+ * Javascript Diff Algorithm
+ * By John Resig (http://ejohn.org/)
+ * Modified by Chu Alan "sprite"
+ *
+ * Released under the MIT license.
+ *
+ * More Info:
+ * http://ejohn.org/projects/javascript-diff-algorithm/
+ *
+ * Usage: QUnit.diff(expected, actual)
+ *
+ * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick <del>brown </del> fox <del>jumped </del><ins>jumps </ins> over"
+ */
+QUnit.diff = (function() {
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ /*jshint eqeqeq:false, eqnull:true */
+ function diff( o, n ) {
+ var i,
+ ns = {},
+ os = {};
+
+ for ( i = 0; i < n.length; i++ ) {
+ if ( !hasOwn.call( ns, n[ i ] ) ) {
+ ns[ n[ i ] ] = {
+ rows: [],
+ o: null
+ };
+ }
+ ns[ n[ i ] ].rows.push( i );
+ }
+
+ for ( i = 0; i < o.length; i++ ) {
+ if ( !hasOwn.call( os, o[ i ] ) ) {
+ os[ o[ i ] ] = {
+ rows: [],
+ n: null
+ };
+ }
+ os[ o[ i ] ].rows.push( i );
+ }
+
+ for ( i in ns ) {
+ if ( hasOwn.call( ns, i ) ) {
+ if ( ns[ i ].rows.length === 1 && hasOwn.call( os, i ) && os[ i ].rows.length === 1 ) {
+ n[ ns[ i ].rows[ 0 ] ] = {
+ text: n[ ns[ i ].rows[ 0 ] ],
+ row: os[ i ].rows[ 0 ]
+ };
+ o[ os[ i ].rows[ 0 ] ] = {
+ text: o[ os[ i ].rows[ 0 ] ],
+ row: ns[ i ].rows[ 0 ]
+ };
+ }
+ }
+ }
+
+ for ( i = 0; i < n.length - 1; i++ ) {
+ if ( n[ i ].text != null && n[ i + 1 ].text == null && n[ i ].row + 1 < o.length && o[ n[ i ].row + 1 ].text == null &&
+ n[ i + 1 ] == o[ n[ i ].row + 1 ] ) {
+
+ n[ i + 1 ] = {
+ text: n[ i + 1 ],
+ row: n[ i ].row + 1
+ };
+ o[ n[ i ].row + 1 ] = {
+ text: o[ n[ i ].row + 1 ],
+ row: i + 1
+ };
+ }
+ }
+
+ for ( i = n.length - 1; i > 0; i-- ) {
+ if ( n[ i ].text != null && n[ i - 1 ].text == null && n[ i ].row > 0 && o[ n[ i ].row - 1 ].text == null &&
+ n[ i - 1 ] == o[ n[ i ].row - 1 ] ) {
+
+ n[ i - 1 ] = {
+ text: n[ i - 1 ],
+ row: n[ i ].row - 1
+ };
+ o[ n[ i ].row - 1 ] = {
+ text: o[ n[ i ].row - 1 ],
+ row: i - 1
+ };
+ }
+ }
+
+ return {
+ o: o,
+ n: n
+ };
+ }
+
+ return function( o, n ) {
+ o = o.replace( /\s+$/, "" );
+ n = n.replace( /\s+$/, "" );
+
+ var i, pre,
+ str = "",
+ out = diff( o === "" ? [] : o.split( /\s+/ ), n === "" ? [] : n.split( /\s+/ ) ),
+ oSpace = o.match( /\s+/g ),
+ nSpace = n.match( /\s+/g );
+
+ if ( oSpace == null ) {
+ oSpace = [ " " ];
+ } else {
+ oSpace.push( " " );
+ }
+
+ if ( nSpace == null ) {
+ nSpace = [ " " ];
+ } else {
+ nSpace.push( " " );
+ }
+
+ if ( out.n.length === 0 ) {
+ for ( i = 0; i < out.o.length; i++ ) {
+ str += "<del>" + out.o[ i ] + oSpace[ i ] + "</del>";
+ }
+ } else {
+ if ( out.n[ 0 ].text == null ) {
+ for ( n = 0; n < out.o.length && out.o[ n ].text == null; n++ ) {
+ str += "<del>" + out.o[ n ] + oSpace[ n ] + "</del>";
+ }
+ }
+
+ for ( i = 0; i < out.n.length; i++ ) {
+ if ( out.n[ i ].text == null ) {
+ str += "<ins>" + out.n[ i ] + nSpace[ i ] + "</ins>";
+ } else {
+
+ // `pre` initialized at top of scope
+ pre = "";
+
+ for ( n = out.n[ i ].row + 1; n < out.o.length && out.o[ n ].text == null; n++ ) {
+ pre += "<del>" + out.o[ n ] + oSpace[ n ] + "</del>";
+ }
+ str += " " + out.n[ i ].text + nSpace[ i ] + pre;
+ }
+ }
+ }
+
+ return str;
+ };
+}());
+// jscs:enable
+
+(function() {
+
+// Deprecated QUnit.init - Ref #530
+// Re-initialize the configuration options
+QUnit.init = function() {
+ var tests, banner, result, qunit,
+ config = QUnit.config;
+
+ config.stats = { all: 0, bad: 0 };
+ config.moduleStats = { all: 0, bad: 0 };
+ config.started = 0;
+ config.updateRate = 1000;
+ config.blocking = false;
+ config.autostart = true;
+ config.autorun = false;
+ config.filter = "";
+ config.queue = [];
+
+ // Return on non-browser environments
+ // This is necessary to not break on node tests
+ if ( typeof window === "undefined" ) {
+ return;
+ }
+
+ qunit = id( "qunit" );
+ if ( qunit ) {
+ qunit.innerHTML =
+ "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
+ "<h2 id='qunit-banner'></h2>" +
+ "<div id='qunit-testrunner-toolbar'></div>" +
+ "<h2 id='qunit-userAgent'></h2>" +
+ "<ol id='qunit-tests'></ol>";
+ }
+
+ tests = id( "qunit-tests" );
+ banner = id( "qunit-banner" );
+ result = id( "qunit-testresult" );
+
+ if ( tests ) {
+ tests.innerHTML = "";
+ }
+
+ if ( banner ) {
+ banner.className = "";
+ }
+
+ if ( result ) {
+ result.parentNode.removeChild( result );
+ }
+
+ if ( tests ) {
+ result = document.createElement( "p" );
+ result.id = "qunit-testresult";
+ result.className = "result";
+ tests.parentNode.insertBefore( result, tests );
+ result.innerHTML = "Running...<br />&#160;";
+ }
+};
+
+// Don't load the HTML Reporter on non-Browser environments
+if ( typeof window === "undefined" ) {
+ return;
+}
+
+var config = QUnit.config,
+ hasOwn = Object.prototype.hasOwnProperty,
+ defined = {
+ document: window.document !== undefined,
+ sessionStorage: (function() {
+ var x = "qunit-test-string";
+ try {
+ sessionStorage.setItem( x, x );
+ sessionStorage.removeItem( x );
+ return true;
+ } catch ( e ) {
+ return false;
+ }
+ }())
+ },
+ modulesList = [];
+
+/**
+* Escape text for attribute or text content.
+*/
+function escapeText( s ) {
+ if ( !s ) {
+ return "";
+ }
+ s = s + "";
+
+ // Both single quotes and double quotes (for attributes)
+ return s.replace( /['"<>&]/g, function( s ) {
+ switch ( s ) {
+ case "'":
+ return "&#039;";
+ case "\"":
+ return "&quot;";
+ case "<":
+ return "&lt;";
+ case ">":
+ return "&gt;";
+ case "&":
+ return "&amp;";
+ }
+ });
+}
+
+/**
+ * @param {HTMLElement} elem
+ * @param {string} type
+ * @param {Function} fn
+ */
+function addEvent( elem, type, fn ) {
+ if ( elem.addEventListener ) {
+
+ // Standards-based browsers
+ elem.addEventListener( type, fn, false );
+ } else if ( elem.attachEvent ) {
+
+ // support: IE <9
+ elem.attachEvent( "on" + type, fn );
+ }
+}
+
+/**
+ * @param {Array|NodeList} elems
+ * @param {string} type
+ * @param {Function} fn
+ */
+function addEvents( elems, type, fn ) {
+ var i = elems.length;
+ while ( i-- ) {
+ addEvent( elems[ i ], type, fn );
+ }
+}
+
+function hasClass( elem, name ) {
+ return ( " " + elem.className + " " ).indexOf( " " + name + " " ) >= 0;
+}
+
+function addClass( elem, name ) {
+ if ( !hasClass( elem, name ) ) {
+ elem.className += ( elem.className ? " " : "" ) + name;
+ }
+}
+
+function toggleClass( elem, name ) {
+ if ( hasClass( elem, name ) ) {
+ removeClass( elem, name );
+ } else {
+ addClass( elem, name );
+ }
+}
+
+function removeClass( elem, name ) {
+ var set = " " + elem.className + " ";
+
+ // Class name may appear multiple times
+ while ( set.indexOf( " " + name + " " ) >= 0 ) {
+ set = set.replace( " " + name + " ", " " );
+ }
+
+ // trim for prettiness
+ elem.className = typeof set.trim === "function" ? set.trim() : set.replace( /^\s+|\s+$/g, "" );
+}
+
+function id( name ) {
+ return defined.document && document.getElementById && document.getElementById( name );
+}
+
+function getUrlConfigHtml() {
+ var i, j, val,
+ escaped, escapedTooltip,
+ selection = false,
+ len = config.urlConfig.length,
+ urlConfigHtml = "";
+
+ for ( i = 0; i < len; i++ ) {
+ val = config.urlConfig[ i ];
+ if ( typeof val === "string" ) {
+ val = {
+ id: val,
+ label: val
+ };
+ }
+
+ escaped = escapeText( val.id );
+ escapedTooltip = escapeText( val.tooltip );
+
+ if ( config[ val.id ] === undefined ) {
+ config[ val.id ] = QUnit.urlParams[ val.id ];
+ }
+
+ if ( !val.value || typeof val.value === "string" ) {
+ urlConfigHtml += "<input id='qunit-urlconfig-" + escaped +
+ "' name='" + escaped + "' type='checkbox'" +
+ ( val.value ? " value='" + escapeText( val.value ) + "'" : "" ) +
+ ( config[ val.id ] ? " checked='checked'" : "" ) +
+ " title='" + escapedTooltip + "' /><label for='qunit-urlconfig-" + escaped +
+ "' title='" + escapedTooltip + "'>" + val.label + "</label>";
+ } else {
+ urlConfigHtml += "<label for='qunit-urlconfig-" + escaped +
+ "' title='" + escapedTooltip + "'>" + val.label +
+ ": </label><select id='qunit-urlconfig-" + escaped +
+ "' name='" + escaped + "' title='" + escapedTooltip + "'><option></option>";
+
+ if ( QUnit.is( "array", val.value ) ) {
+ for ( j = 0; j < val.value.length; j++ ) {
+ escaped = escapeText( val.value[ j ] );
+ urlConfigHtml += "<option value='" + escaped + "'" +
+ ( config[ val.id ] === val.value[ j ] ?
+ ( selection = true ) && " selected='selected'" : "" ) +
+ ">" + escaped + "</option>";
+ }
+ } else {
+ for ( j in val.value ) {
+ if ( hasOwn.call( val.value, j ) ) {
+ urlConfigHtml += "<option value='" + escapeText( j ) + "'" +
+ ( config[ val.id ] === j ?
+ ( selection = true ) && " selected='selected'" : "" ) +
+ ">" + escapeText( val.value[ j ] ) + "</option>";
+ }
+ }
+ }
+ if ( config[ val.id ] && !selection ) {
+ escaped = escapeText( config[ val.id ] );
+ urlConfigHtml += "<option value='" + escaped +
+ "' selected='selected' disabled='disabled'>" + escaped + "</option>";
+ }
+ urlConfigHtml += "</select>";
+ }
+ }
+
+ return urlConfigHtml;
+}
+
+// Handle "click" events on toolbar checkboxes and "change" for select menus.
+// Updates the URL with the new state of `config.urlConfig` values.
+function toolbarChanged() {
+ var updatedUrl, value,
+ field = this,
+ params = {};
+
+ // Detect if field is a select menu or a checkbox
+ if ( "selectedIndex" in field ) {
+ value = field.options[ field.selectedIndex ].value || undefined;
+ } else {
+ value = field.checked ? ( field.defaultValue || true ) : undefined;
+ }
+
+ params[ field.name ] = value;
+ updatedUrl = setUrl( params );
+
+ if ( "hidepassed" === field.name && "replaceState" in window.history ) {
+ config[ field.name ] = value || false;
+ if ( value ) {
+ addClass( id( "qunit-tests" ), "hidepass" );
+ } else {
+ removeClass( id( "qunit-tests" ), "hidepass" );
+ }
+
+ // It is not necessary to refresh the whole page
+ window.history.replaceState( null, "", updatedUrl );
+ } else {
+ window.location = updatedUrl;
+ }
+}
+
+function setUrl( params ) {
+ var key,
+ querystring = "?";
+
+ params = QUnit.extend( QUnit.extend( {}, QUnit.urlParams ), params );
+
+ for ( key in params ) {
+ if ( hasOwn.call( params, key ) ) {
+ if ( params[ key ] === undefined ) {
+ continue;
+ }
+ querystring += encodeURIComponent( key );
+ if ( params[ key ] !== true ) {
+ querystring += "=" + encodeURIComponent( params[ key ] );
+ }
+ querystring += "&";
+ }
+ }
+ return location.protocol + "//" + location.host +
+ location.pathname + querystring.slice( 0, -1 );
+}
+
+function applyUrlParams() {
+ var selectBox = id( "qunit-modulefilter" ),
+ selection = decodeURIComponent( selectBox.options[ selectBox.selectedIndex ].value ),
+ filter = id( "qunit-filter-input" ).value;
+
+ window.location = setUrl({
+ module: ( selection === "" ) ? undefined : selection,
+ filter: ( filter === "" ) ? undefined : filter,
+
+ // Remove testId filter
+ testId: undefined
+ });
+}
+
+function toolbarUrlConfigContainer() {
+ var urlConfigContainer = document.createElement( "span" );
+
+ urlConfigContainer.innerHTML = getUrlConfigHtml();
+ addClass( urlConfigContainer, "qunit-url-config" );
+
+ // For oldIE support:
+ // * Add handlers to the individual elements instead of the container
+ // * Use "click" instead of "change" for checkboxes
+ addEvents( urlConfigContainer.getElementsByTagName( "input" ), "click", toolbarChanged );
+ addEvents( urlConfigContainer.getElementsByTagName( "select" ), "change", toolbarChanged );
+
+ return urlConfigContainer;
+}
+
+function toolbarLooseFilter() {
+ var filter = document.createElement( "form" ),
+ label = document.createElement( "label" ),
+ input = document.createElement( "input" ),
+ button = document.createElement( "button" );
+
+ addClass( filter, "qunit-filter" );
+
+ label.innerHTML = "Filter: ";
+
+ input.type = "text";
+ input.value = config.filter || "";
+ input.name = "filter";
+ input.id = "qunit-filter-input";
+
+ button.innerHTML = "Go";
+
+ label.appendChild( input );
+
+ filter.appendChild( label );
+ filter.appendChild( button );
+ addEvent( filter, "submit", function( ev ) {
+ applyUrlParams();
+
+ if ( ev && ev.preventDefault ) {
+ ev.preventDefault();
+ }
+
+ return false;
+ });
+
+ return filter;
+}
+
+function toolbarModuleFilterHtml() {
+ var i,
+ moduleFilterHtml = "";
+
+ if ( !modulesList.length ) {
+ return false;
+ }
+
+ modulesList.sort(function( a, b ) {
+ return a.localeCompare( b );
+ });
+
+ moduleFilterHtml += "<label for='qunit-modulefilter'>Module: </label>" +
+ "<select id='qunit-modulefilter' name='modulefilter'><option value='' " +
+ ( QUnit.urlParams.module === undefined ? "selected='selected'" : "" ) +
+ ">< All Modules ></option>";
+
+ for ( i = 0; i < modulesList.length; i++ ) {
+ moduleFilterHtml += "<option value='" +
+ escapeText( encodeURIComponent( modulesList[ i ] ) ) + "' " +
+ ( QUnit.urlParams.module === modulesList[ i ] ? "selected='selected'" : "" ) +
+ ">" + escapeText( modulesList[ i ] ) + "</option>";
+ }
+ moduleFilterHtml += "</select>";
+
+ return moduleFilterHtml;
+}
+
+function toolbarModuleFilter() {
+ var toolbar = id( "qunit-testrunner-toolbar" ),
+ moduleFilter = document.createElement( "span" ),
+ moduleFilterHtml = toolbarModuleFilterHtml();
+
+ if ( !toolbar || !moduleFilterHtml ) {
+ return false;
+ }
+
+ moduleFilter.setAttribute( "id", "qunit-modulefilter-container" );
+ moduleFilter.innerHTML = moduleFilterHtml;
+
+ addEvent( moduleFilter.lastChild, "change", applyUrlParams );
+
+ toolbar.appendChild( moduleFilter );
+}
+
+function appendToolbar() {
+ var toolbar = id( "qunit-testrunner-toolbar" );
+
+ if ( toolbar ) {
+ toolbar.appendChild( toolbarUrlConfigContainer() );
+ toolbar.appendChild( toolbarLooseFilter() );
+ }
+}
+
+function appendHeader() {
+ var header = id( "qunit-header" );
+
+ if ( header ) {
+ header.innerHTML = "<a href='" +
+ setUrl({ filter: undefined, module: undefined, testId: undefined }) +
+ "'>" + header.innerHTML + "</a> ";
+ }
+}
+
+function appendBanner() {
+ var banner = id( "qunit-banner" );
+
+ if ( banner ) {
+ banner.className = "";
+ }
+}
+
+function appendTestResults() {
+ var tests = id( "qunit-tests" ),
+ result = id( "qunit-testresult" );
+
+ if ( result ) {
+ result.parentNode.removeChild( result );
+ }
+
+ if ( tests ) {
+ tests.innerHTML = "";
+ result = document.createElement( "p" );
+ result.id = "qunit-testresult";
+ result.className = "result";
+ tests.parentNode.insertBefore( result, tests );
+ result.innerHTML = "Running...<br />&#160;";
+ }
+}
+
+function storeFixture() {
+ var fixture = id( "qunit-fixture" );
+ if ( fixture ) {
+ config.fixture = fixture.innerHTML;
+ }
+}
+
+function appendUserAgent() {
+ var userAgent = id( "qunit-userAgent" );
+ if ( userAgent ) {
+ userAgent.innerHTML = "";
+ userAgent.appendChild( document.createTextNode( navigator.userAgent ) );
+ }
+}
+
+function appendTestsList( modules ) {
+ var i, l, x, z, test, moduleObj;
+
+ for ( i = 0, l = modules.length; i < l; i++ ) {
+ moduleObj = modules[ i ];
+
+ if ( moduleObj.name ) {
+ modulesList.push( moduleObj.name );
+ }
+
+ for ( x = 0, z = moduleObj.tests.length; x < z; x++ ) {
+ test = moduleObj.tests[ x ];
+
+ appendTest( test.name, test.testId, moduleObj.name );
+ }
+ }
+}
+
+function appendTest( name, testId, moduleName ) {
+ var title, rerunTrigger, testBlock, assertList,
+ tests = id( "qunit-tests" );
+
+ if ( !tests ) {
+ return;
+ }
+
+ title = document.createElement( "strong" );
+ title.innerHTML = getNameHtml( name, moduleName );
+
+ rerunTrigger = document.createElement( "a" );
+ rerunTrigger.innerHTML = "Rerun";
+ rerunTrigger.href = setUrl({ testId: testId });
+
+ testBlock = document.createElement( "li" );
+ testBlock.appendChild( title );
+ testBlock.appendChild( rerunTrigger );
+ testBlock.id = "qunit-test-output-" + testId;
+
+ assertList = document.createElement( "ol" );
+ assertList.className = "qunit-assert-list";
+
+ testBlock.appendChild( assertList );
+
+ tests.appendChild( testBlock );
+}
+
+// HTML Reporter initialization and load
+QUnit.begin(function( details ) {
+ var qunit = id( "qunit" );
+
+ // Fixture is the only one necessary to run without the #qunit element
+ storeFixture();
+
+ if ( qunit ) {
+ qunit.innerHTML =
+ "<h1 id='qunit-header'>" + escapeText( document.title ) + "</h1>" +
+ "<h2 id='qunit-banner'></h2>" +
+ "<div id='qunit-testrunner-toolbar'></div>" +
+ "<h2 id='qunit-userAgent'></h2>" +
+ "<ol id='qunit-tests'></ol>";
+ }
+
+ appendHeader();
+ appendBanner();
+ appendTestResults();
+ appendUserAgent();
+ appendToolbar();
+ appendTestsList( details.modules );
+ toolbarModuleFilter();
+
+ if ( qunit && config.hidepassed ) {
+ addClass( qunit.lastChild, "hidepass" );
+ }
+});
+
+QUnit.done(function( details ) {
+ var i, key,
+ banner = id( "qunit-banner" ),
+ tests = id( "qunit-tests" ),
+ html = [
+ "Tests completed in ",
+ details.runtime,
+ " milliseconds.<br />",
+ "<span class='passed'>",
+ details.passed,
+ "</span> assertions of <span class='total'>",
+ details.total,
+ "</span> passed, <span class='failed'>",
+ details.failed,
+ "</span> failed."
+ ].join( "" );
+
+ if ( banner ) {
+ banner.className = details.failed ? "qunit-fail" : "qunit-pass";
+ }
+
+ if ( tests ) {
+ id( "qunit-testresult" ).innerHTML = html;
+ }
+
+ if ( config.altertitle && defined.document && document.title ) {
+
+ // show ✖ for good, ✔ for bad suite result in title
+ // use escape sequences in case file gets loaded with non-utf-8-charset
+ document.title = [
+ ( details.failed ? "\u2716" : "\u2714" ),
+ document.title.replace( /^[\u2714\u2716] /i, "" )
+ ].join( " " );
+ }
+
+ // clear own sessionStorage items if all tests passed
+ if ( config.reorder && defined.sessionStorage && details.failed === 0 ) {
+ for ( i = 0; i < sessionStorage.length; i++ ) {
+ key = sessionStorage.key( i++ );
+ if ( key.indexOf( "qunit-test-" ) === 0 ) {
+ sessionStorage.removeItem( key );
+ }
+ }
+ }
+
+ // scroll back to top to show results
+ if ( config.scrolltop && window.scrollTo ) {
+ window.scrollTo( 0, 0 );
+ }
+});
+
+function getNameHtml( name, module ) {
+ var nameHtml = "";
+
+ if ( module ) {
+ nameHtml = "<span class='module-name'>" + escapeText( module ) + "</span>: ";
+ }
+
+ nameHtml += "<span class='test-name'>" + escapeText( name ) + "</span>";
+
+ return nameHtml;
+}
+
+QUnit.testStart(function( details ) {
+ var running, testBlock;
+
+ testBlock = id( "qunit-test-output-" + details.testId );
+ if ( testBlock ) {
+ testBlock.className = "running";
+ } else {
+
+ // Report later registered tests
+ appendTest( details.name, details.testId, details.module );
+ }
+
+ running = id( "qunit-testresult" );
+ if ( running ) {
+ running.innerHTML = "Running: <br />" + getNameHtml( details.name, details.module );
+ }
+
+});
+
+QUnit.log(function( details ) {
+ var assertList, assertLi,
+ message, expected, actual,
+ testItem = id( "qunit-test-output-" + details.testId );
+
+ if ( !testItem ) {
+ return;
+ }
+
+ message = escapeText( details.message ) || ( details.result ? "okay" : "failed" );
+ message = "<span class='test-message'>" + message + "</span>";
+ message += "<span class='runtime'>@ " + details.runtime + " ms</span>";
+
+ // pushFailure doesn't provide details.expected
+ // when it calls, it's implicit to also not show expected and diff stuff
+ // Also, we need to check details.expected existence, as it can exist and be undefined
+ if ( !details.result && hasOwn.call( details, "expected" ) ) {
+ expected = escapeText( QUnit.dump.parse( details.expected ) );
+ actual = escapeText( QUnit.dump.parse( details.actual ) );
+ message += "<table><tr class='test-expected'><th>Expected: </th><td><pre>" +
+ expected +
+ "</pre></td></tr>";
+
+ if ( actual !== expected ) {
+ message += "<tr class='test-actual'><th>Result: </th><td><pre>" +
+ actual + "</pre></td></tr>" +
+ "<tr class='test-diff'><th>Diff: </th><td><pre>" +
+ QUnit.diff( expected, actual ) + "</pre></td></tr>";
+ }
+
+ if ( details.source ) {
+ message += "<tr class='test-source'><th>Source: </th><td><pre>" +
+ escapeText( details.source ) + "</pre></td></tr>";
+ }
+
+ message += "</table>";
+
+ // this occours when pushFailure is set and we have an extracted stack trace
+ } else if ( !details.result && details.source ) {
+ message += "<table>" +
+ "<tr class='test-source'><th>Source: </th><td><pre>" +
+ escapeText( details.source ) + "</pre></td></tr>" +
+ "</table>";
+ }
+
+ assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
+
+ assertLi = document.createElement( "li" );
+ assertLi.className = details.result ? "pass" : "fail";
+ assertLi.innerHTML = message;
+ assertList.appendChild( assertLi );
+});
+
+QUnit.testDone(function( details ) {
+ var testTitle, time, testItem, assertList,
+ good, bad, testCounts, skipped,
+ tests = id( "qunit-tests" );
+
+ if ( !tests ) {
+ return;
+ }
+
+ testItem = id( "qunit-test-output-" + details.testId );
+
+ assertList = testItem.getElementsByTagName( "ol" )[ 0 ];
+
+ good = details.passed;
+ bad = details.failed;
+
+ // store result when possible
+ if ( config.reorder && defined.sessionStorage ) {
+ if ( bad ) {
+ sessionStorage.setItem( "qunit-test-" + details.module + "-" + details.name, bad );
+ } else {
+ sessionStorage.removeItem( "qunit-test-" + details.module + "-" + details.name );
+ }
+ }
+
+ if ( bad === 0 ) {
+ addClass( assertList, "qunit-collapsed" );
+ }
+
+ // testItem.firstChild is the test name
+ testTitle = testItem.firstChild;
+
+ testCounts = bad ?
+ "<b class='failed'>" + bad + "</b>, " + "<b class='passed'>" + good + "</b>, " :
+ "";
+
+ testTitle.innerHTML += " <b class='counts'>(" + testCounts +
+ details.assertions.length + ")</b>";
+
+ if ( details.skipped ) {
+ testItem.className = "skipped";
+ skipped = document.createElement( "em" );
+ skipped.className = "qunit-skipped-label";
+ skipped.innerHTML = "skipped";
+ testItem.insertBefore( skipped, testTitle );
+ } else {
+ addEvent( testTitle, "click", function() {
+ toggleClass( assertList, "qunit-collapsed" );
+ });
+
+ testItem.className = bad ? "fail" : "pass";
+
+ time = document.createElement( "span" );
+ time.className = "runtime";
+ time.innerHTML = details.runtime + " ms";
+ testItem.insertBefore( time, assertList );
+ }
+});
+
+if ( !defined.document || document.readyState === "complete" ) {
+ config.pageLoaded = true;
+ config.autorun = true;
+}
+
+if ( defined.document ) {
+ addEvent( window, "load", QUnit.load );
+}
+
+})();
diff --git a/resources/src/jquery.json-deprecate.js b/resources/src/jquery.json-deprecate.js
deleted file mode 100644
index f38decd9..00000000
--- a/resources/src/jquery.json-deprecate.js
+++ /dev/null
@@ -1,8 +0,0 @@
-( function ( mw, $ ) {
- // @deprecated since 1.24. The 'jquery.json' module will be removed in MW 1.25. Use the 'json' module.
-
- mw.log.deprecate( $, 'toJSON', $.toJSON, 'Use JSON.stringify instead (module "json" for polyfill).' );
- mw.log.deprecate( $, 'evalJSON', $.evalJSON, 'Use JSON.parse instead (module "json" for polyfill).' );
- mw.log.deprecate( $, 'secureEvalJSON', $.secureEvalJSON, 'Use JSON.parse instead (module "json" for polyfill).' );
- mw.log.deprecate( $, 'quoteString', $.quoteString, 'Use JSON.stringify instead (module "json" for polyfill).' );
-}( mediaWiki, jQuery ) );
diff --git a/resources/src/jquery.tipsy/jquery.tipsy.js b/resources/src/jquery.tipsy/jquery.tipsy.js
index 58a99a59..2a37fa86 100644
--- a/resources/src/jquery.tipsy/jquery.tipsy.js
+++ b/resources/src/jquery.tipsy/jquery.tipsy.js
@@ -6,7 +6,7 @@
// * This installation of tipsy includes several local modifications to both Javascript and CSS.
// Please be careful when upgrading.
-(function($) {
+( function ( mw, $ ) {
function maybeCall(thing, ctx) {
return (typeof thing == 'function') ? (thing.call(ctx)) : thing;
@@ -182,11 +182,22 @@
if (!options.live) this.each(function() { get(this); });
- if (options.trigger != 'manual') {
- var binder = options.live ? 'live' : 'bind',
- eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus',
+ if ( options.trigger != 'manual' ) {
+ var eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus',
eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur';
- this[binder](eventIn, enter)[binder](eventOut, leave);
+ if ( options.live ) {
+ mw.track( 'mw.deprecate', 'tipsy-live' );
+ mw.log.warn( 'Use of the "live" option of jquery.tipsy is deprecated.' );
+ // XXX: The official status of 'context' is deprecated, and the official status of
+ // 'selector' is removed, so this really needs to go.
+ $( this.context )
+ .on( eventIn, this.selector, enter )
+ .on( eventOut, this.selector, leave );
+ } else {
+ this
+ .on( eventIn, enter )
+ .on( eventOut, leave );
+ }
}
return this;
@@ -256,4 +267,4 @@
}
};
-})(jQuery);
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/jquery/jquery.accessKeyLabel.js b/resources/src/jquery/jquery.accessKeyLabel.js
index 7b49cb2d..867c25e7 100644
--- a/resources/src/jquery/jquery.accessKeyLabel.js
+++ b/resources/src/jquery/jquery.accessKeyLabel.js
@@ -8,7 +8,7 @@
// Cached access key prefix for used browser
var cachedAccessKeyPrefix,
- // Wether to use 'test-' instead of correct prefix (used for testing)
+ // Whether to use 'test-' instead of correct prefix (used for testing)
useTestPrefix = false,
// tag names which can have a label tag
diff --git a/resources/src/jquery/jquery.arrowSteps.js b/resources/src/jquery/jquery.arrowSteps.js
index f8641e10..629ce32c 100644
--- a/resources/src/jquery/jquery.arrowSteps.js
+++ b/resources/src/jquery/jquery.arrowSteps.js
@@ -80,7 +80,7 @@
$.each( $steps, function ( i, step ) {
var $step = $( step );
if ( $step.is( selector ) ) {
- if ($previous) {
+ if ( $previous ) {
$previous.addClass( 'tail' );
}
$step.addClass( 'head' );
diff --git a/resources/src/jquery/jquery.badge.css b/resources/src/jquery/jquery.badge.css
index fa7ea702..34cdf76c 100644
--- a/resources/src/jquery/jquery.badge.css
+++ b/resources/src/jquery/jquery.badge.css
@@ -13,7 +13,7 @@
font-weight: bold;
color: white;
vertical-align: baseline;
- text-shadow: 0 1px rgba(0, 0, 0, 0.4);
+ text-shadow: 0 1px rgba(0, 0, 0, 0.4);
}
.mw-badge-inline {
diff --git a/resources/src/jquery/jquery.badge.js b/resources/src/jquery/jquery.badge.js
index 023b6e28..77738661 100644
--- a/resources/src/jquery/jquery.badge.js
+++ b/resources/src/jquery/jquery.badge.js
@@ -45,7 +45,8 @@
$.fn.badge = function ( text, inline, displayZero ) {
var $badge = this.find( '.mw-badge' ),
badgeStyleClass = 'mw-badge-' + ( inline ? 'inline' : 'overlay' ),
- isImportant = true, displayBadge = true;
+ isImportant = true,
+ displayBadge = true;
// If we're displaying zero, ensure style to be non-important
if ( mw.language.convertNumber( text, true ) === 0 ) {
diff --git a/resources/src/jquery/jquery.confirmable.js b/resources/src/jquery/jquery.confirmable.js
index 339e65a4..1ecce6ca 100644
--- a/resources/src/jquery/jquery.confirmable.js
+++ b/resources/src/jquery/jquery.confirmable.js
@@ -40,6 +40,8 @@
* @param {string} [options.i18n.confirm] Text to use for the confirmation question.
* @param {string} [options.i18n.yes] Text to use for the 'Yes' button.
* @param {string} [options.i18n.no] Text to use for the 'No' button.
+ * @param {string} [options.i18n.yesTitle] Title text to use for the 'Yes' button.
+ * @param {string} [options.i18n.noTitle] Title text to use for the 'No' button.
*
* @chainable
*/
@@ -108,6 +110,9 @@
if ( options.handler ) {
$buttonYes.on( options.events, options.handler );
}
+ if ( options.i18n.yesTitle ) {
+ $buttonYes.attr( 'title', options.i18n.yesTitle );
+ }
$buttonYes = options.buttonCallback( $buttonYes, 'yes' );
// Clone it without any events and prevent default action to represent the 'No' button.
@@ -120,6 +125,11 @@
$interface.css( 'width', 0 );
e.preventDefault();
} );
+ if ( options.i18n.noTitle ) {
+ $buttonNo.attr( 'title', options.i18n.noTitle );
+ } else {
+ $buttonNo.removeAttr( 'title' );
+ }
$buttonNo = options.buttonCallback( $buttonNo, 'no' );
// Prevent memory leaks
@@ -164,7 +174,9 @@
space: ' ',
confirm: 'Are you sure?',
yes: 'Yes',
- no: 'No'
+ no: 'No',
+ yesTitle: undefined,
+ noTitle: undefined
}
};
}( jQuery ) );
diff --git a/resources/src/jquery/jquery.confirmable.mediawiki.js b/resources/src/jquery/jquery.confirmable.mediawiki.js
index d4a106e3..daf23a99 100644
--- a/resources/src/jquery/jquery.confirmable.mediawiki.js
+++ b/resources/src/jquery/jquery.confirmable.mediawiki.js
@@ -9,6 +9,8 @@
space: mw.message( 'word-separator' ).text(),
confirm: mw.message( 'confirmable-confirm', mw.user ).text(),
yes: mw.message( 'confirmable-yes' ).text(),
- no: mw.message( 'confirmable-no' ).text()
+ no: mw.message( 'confirmable-no' ).text(),
+ yesTitle: undefined,
+ noTitle: undefined
};
}( mediaWiki, jQuery ) );
diff --git a/resources/src/jquery/jquery.expandableField.js b/resources/src/jquery/jquery.expandableField.js
index 732cc6ec..48341bc5 100644
--- a/resources/src/jquery/jquery.expandableField.js
+++ b/resources/src/jquery/jquery.expandableField.js
@@ -134,7 +134,7 @@
// Store the context for next time
$( this ).data( 'expandableField-context', context );
} );
- return returnValue !== undefined ? returnValue : $(this);
+ return returnValue !== undefined ? returnValue : $( this );
};
}( jQuery ) );
diff --git a/resources/src/jquery/jquery.footHovzer.js b/resources/src/jquery/jquery.footHovzer.js
index de745c33..e601ddb1 100644
--- a/resources/src/jquery/jquery.footHovzer.js
+++ b/resources/src/jquery/jquery.footHovzer.js
@@ -2,7 +2,7 @@
* @class jQuery.plugin.footHovzer
*/
( function ( $ ) {
- var $hovzer, footHovzer, prevHeight, newHeight;
+ var $hovzer, footHovzer, $spacer;
function getHovzer() {
if ( $hovzer === undefined ) {
@@ -46,15 +46,15 @@
var $body;
$body = $( 'body' );
- if ( prevHeight === undefined ) {
- prevHeight = getHovzer().outerHeight( /* includeMargin = */ true );
- $body.css( 'paddingBottom', '+=' + prevHeight + 'px' );
- } else {
- newHeight = getHovzer().outerHeight( true );
- $body.css( 'paddingBottom', ( parseFloat( $body.css( 'paddingBottom' ) ) - prevHeight ) + newHeight );
- prevHeight = newHeight;
+ if ( $spacer === undefined ) {
+ $spacer = $( '<div>' ).attr( 'id', 'jquery-foot-hovzer-spacer' );
+ $spacer.appendTo( $body );
}
+ // Ensure CSS is applied by browser before using .outerHeight()
+ setTimeout( function () {
+ $spacer.css( 'height', getHovzer().outerHeight( /* includeMargin = */ true ) );
+ }, 0 );
}
};
diff --git a/resources/src/jquery/jquery.getAttrs.js b/resources/src/jquery/jquery.getAttrs.js
index c44831c4..64827fb7 100644
--- a/resources/src/jquery/jquery.getAttrs.js
+++ b/resources/src/jquery/jquery.getAttrs.js
@@ -2,38 +2,37 @@
* @class jQuery.plugin.getAttrs
*/
+function serializeControls( controls ) {
+ var i,
+ data = {},
+ len = controls.length;
+
+ for ( i = 0; i < len; i++ ) {
+ data[ controls[i].name ] = controls[i].value;
+ }
+
+ return data;
+}
+
/**
* Get the attributes of an element directy as a plain object.
*
- * If there are more elements in the collection, like most jQuery get/read methods,
- * this method will use the first element in the collection.
- *
- * In IE6, the `attributes` map of a node includes *all* allowed attributes
- * for an element (including those not set). Those will have values like
- * `undefined`, `null`, `0`, `false`, `""` or `"inherit"`.
+ * If there is more than one element in the collection, similar to most other jQuery getter methods,
+ * this will use the first element in the collection.
*
- * However there may be attributes genuinely set to one of those values, and there
- * is no way to distinguish between attributes set to that and those not set and
- * it being the default. If you need them, set `all` to `true`. They are filtered out
- * by default.
- *
- * @param {boolean} [all=false]
* @return {Object}
*/
-jQuery.fn.getAttrs = function ( all ) {
- var map = this[0].attributes,
- attrs = {},
- len = map.length,
- i, v;
-
- for ( i = 0; i < len; i++ ) {
- v = map[i].nodeValue;
- if ( all || ( v && v !== 'inherit' ) ) {
- attrs[ map[i].nodeName ] = v;
- }
- }
+jQuery.fn.getAttrs = function () {
+ return serializeControls( this[0].attributes );
+};
- return attrs;
+/**
+ * Get form data as a plain object mapping form control names to their values.
+ *
+ * @return {Object}
+ */
+jQuery.fn.serializeObject = function () {
+ return serializeControls( this.serializeArray() );
};
/**
diff --git a/resources/src/jquery/jquery.hidpi.js b/resources/src/jquery/jquery.hidpi.js
index 4ecfeb88..8fca0567 100644
--- a/resources/src/jquery/jquery.hidpi.js
+++ b/resources/src/jquery/jquery.hidpi.js
@@ -73,11 +73,11 @@ $.fn.hidpi = function () {
match;
if ( typeof srcset === 'string' && srcset !== '' ) {
match = $.matchSrcSet( devicePixelRatio, srcset );
- if (match !== null ) {
+ if ( match !== null ) {
$img.attr( 'src', match );
}
}
- });
+ } );
}
return $target;
diff --git a/resources/src/jquery/jquery.makeCollapsible.css b/resources/src/jquery/jquery.makeCollapsible.css
index 0f471509..2e5efbac 100644
--- a/resources/src/jquery/jquery.makeCollapsible.css
+++ b/resources/src/jquery/jquery.makeCollapsible.css
@@ -6,18 +6,38 @@
-ms-user-select: none;
user-select: none;
}
+/* Align the toggle based on the direction of the content language */
+/* @noflip */
+.mw-content-ltr .mw-collapsible-toggle,
+.mw-content-rtl .mw-content-ltr .mw-collapsible-toggle {
+ float: right;
+}
+/* @noflip */
+.mw-content-rtl .mw-collapsible-toggle,
+.mw-content-ltr .mw-content-rtl .mw-collapsible-toggle {
+ float: left;
+}
+
.mw-customtoggle,
.mw-collapsible-toggle {
cursor: pointer;
}
/* collapse links in captions should be inline */
-caption .mw-collapsible-toggle {
+caption .mw-collapsible-toggle,
+.mw-content-ltr caption .mw-collapsible-toggle,
+.mw-content-rtl caption .mw-collapsible-toggle,
+.mw-content-rtl .mw-content-ltr caption .mw-collapsible-toggle,
+.mw-content-ltr .mw-content-rtl caption .mw-collapsible-toggle {
float: none;
}
/* list-items go as wide as their parent element, don't float them inside list items */
-li .mw-collapsible-toggle {
+li .mw-collapsible-toggle,
+.mw-content-ltr li .mw-collapsible-toggle,
+.mw-content-rtl li .mw-collapsible-toggle,
+.mw-content-rtl .mw-content-ltr li .mw-collapsible-toggle,
+.mw-content-ltr .mw-content-rtl li .mw-collapsible-toggle {
float: none;
}
diff --git a/resources/src/jquery/jquery.makeCollapsible.js b/resources/src/jquery/jquery.makeCollapsible.js
index c4e25203..f7c42177 100644
--- a/resources/src/jquery/jquery.makeCollapsible.js
+++ b/resources/src/jquery/jquery.makeCollapsible.js
@@ -208,7 +208,7 @@
* Enable collapsible-functionality on all elements in the collection.
*
* - Will prevent binding twice to the same element.
- * - Initial state is expanded by default, this can be overriden by adding class
+ * - Initial state is expanded by default, this can be overridden by adding class
* "mw-collapsed" to the "mw-collapsible" element.
* - Elements made collapsible have jQuery data "mw-made-collapsible" set to true.
* - The inner content is wrapped in a "div.mw-collapsible-content" (except for tables and lists).
@@ -330,7 +330,7 @@
.prop( 'tabIndex', 0 );
}
} else {
- // The toggle-link will be in one the the cells (td or th) of the first row
+ // The toggle-link will be in one of the cells (td or th) of the first row
$firstItem = $collapsible.find( 'tr:first th, tr:first td' );
$toggle = $firstItem.find( '> .mw-collapsible-toggle' );
diff --git a/resources/src/jquery/jquery.mwExtension.js b/resources/src/jquery/jquery.mwExtension.js
index dc7aaa45..e6e33ade 100644
--- a/resources/src/jquery/jquery.mwExtension.js
+++ b/resources/src/jquery/jquery.mwExtension.js
@@ -15,16 +15,16 @@
return str.charAt( 0 ).toUpperCase() + str.slice( 1 );
},
escapeRE: function ( str ) {
- return str.replace ( /([\\{}()|.?*+\-\^$\[\]])/g, '\\$1' );
+ return str.replace( /([\\{}()|.?*+\-\^$\[\]])/g, '\\$1' );
},
isDomElement: function ( el ) {
return !!el && !!el.nodeType;
},
isEmpty: function ( v ) {
var key;
- if ( v === '' || v === 0 || v === '0' || v === null
- || v === false || v === undefined )
- {
+ if (
+ v === '' || v === 0 || v === '0' || v === null || v === false || v === undefined
+ ) {
return true;
}
// the for-loop could potentially contain prototypes
diff --git a/resources/src/jquery/jquery.placeholder.js b/resources/src/jquery/jquery.placeholder.js
index d4580190..d50422e2 100644
--- a/resources/src/jquery/jquery.placeholder.js
+++ b/resources/src/jquery/jquery.placeholder.js
@@ -13,7 +13,7 @@
* @version 2.1.0
* @license MIT
*/
-(function ($) {
+( function ($) {
var isInputSupported = 'placeholder' in document.createElement('input'),
isTextareaSupported = 'placeholder' in document.createElement('textarea'),
@@ -49,7 +49,7 @@
$this
.filter((isInputSupported ? 'textarea' : ':input') + '[placeholder]')
- .filter(function () {
+ .filter( function () {
return !$(this).data('placeholder-enabled');
})
.bind({
@@ -114,12 +114,12 @@
propHooks.value = hooks;
}
- $(function () {
+ $( function () {
// Look for forms
$(document).delegate('form', 'submit.placeholder', function () {
// Clear the placeholder values so they don't get submitted
var $inputs = $('.placeholder', this).each(clearPlaceholder);
- setTimeout(function () {
+ setTimeout( function () {
$inputs.each(setPlaceholder);
}, 10);
});
@@ -127,7 +127,7 @@
// Clear placeholder values upon page reload
$(window).bind('beforeunload.placeholder', function () {
- $('.placeholder').each(function () {
+ $('.placeholder').each( function () {
this.value = '';
});
});
diff --git a/resources/src/jquery/jquery.qunit.completenessTest.js b/resources/src/jquery/jquery.qunit.completenessTest.js
index 8d38401e..556bf8c7 100644
--- a/resources/src/jquery/jquery.qunit.completenessTest.js
+++ b/resources/src/jquery/jquery.qunit.completenessTest.js
@@ -17,8 +17,8 @@
var util,
hasOwn = Object.prototype.hasOwnProperty,
- log = (window.console && window.console.log)
- ? function () { return window.console.log.apply(window.console, arguments); }
+ log = ( window.console && window.console.log )
+ ? function () { return window.console.log.apply( window.console, arguments ); }
: function () {};
// Simplified version of a few jQuery methods, except that they don't
@@ -91,7 +91,7 @@
// Restore warnings
mw.log.warn = warn;
warn = undefined;
- });
+ } );
QUnit.done( function () {
that.populateMissingTests();
@@ -114,7 +114,7 @@
var elItem = document.createElement( 'li' );
elItem.textContent = key;
elList.appendChild( elItem );
- });
+ } );
elFoot = document.createElement( 'p' );
elFoot.innerHTML = '<em>&mdash; CompletenessTest</em>';
@@ -133,7 +133,7 @@
util.each( style, function ( key, value ) {
elOutputWrapper.style[key] = value;
- });
+ } );
return elOutputWrapper;
}
@@ -171,7 +171,7 @@
if ( toolbar ) {
toolbar.insertBefore( testResults, toolbar.firstChild );
}
- });
+ } );
return this;
}
@@ -248,7 +248,7 @@
var ct = this;
util.each( ct.injectionTracker, function ( key ) {
ct.hasTest( key );
- });
+ } );
},
/**
diff --git a/resources/src/jquery/jquery.suggestions.js b/resources/src/jquery/jquery.suggestions.js
index 3369cde2..813c37ce 100644
--- a/resources/src/jquery/jquery.suggestions.js
+++ b/resources/src/jquery/jquery.suggestions.js
@@ -1,58 +1,102 @@
/**
* This plugin provides a generic way to add suggestions to a text box.
*
- * Usage:
- *
* Set options:
+ *
* $( '#textbox' ).suggestions( { option1: value1, option2: value2 } );
* $( '#textbox' ).suggestions( option, value );
+ *
* Get option:
+ *
* value = $( '#textbox' ).suggestions( option );
+ *
* Initialize:
+ *
* $( '#textbox' ).suggestions();
*
- * Options:
+ * Uses jQuery.suggestions singleteon internally.
*
- * fetch(query): Callback that should fetch suggestions and set the suggestions property.
- * Executed in the context of the textbox
- * Type: Function
- * cancel: Callback function to call when any pending asynchronous suggestions fetches
- * should be canceled. Executed in the context of the textbox
- * Type: Function
- * special: Set of callbacks for rendering and selecting
- * Type: Object of Functions 'render' and 'select'
- * result: Set of callbacks for rendering and selecting
- * Type: Object of Functions 'render' and 'select'
- * $region: jQuery selection of element to place the suggestions below and match width of
- * Type: jQuery Object, Default: $( this )
- * suggestions: Suggestions to display
- * Type: Array of strings
- * maxRows: Maximum number of suggestions to display at one time
- * Type: Number, Range: 1 - 100, Default: 7
- * delay: Number of ms to wait for the user to stop typing
- * Type: Number, Range: 0 - 1200, Default: 120
- * cache: Whether to cache results from a fetch
- * Type: Boolean, Default: false
- * cacheMaxAge: Number of ms to cache results from a fetch
- * Type: Number, Range: 1 - Infinity, Default: 60000 (1 minute)
- * submitOnClick: Whether to submit the form containing the textbox when a suggestion is clicked
- * Type: Boolean, Default: false
- * maxExpandFactor: Maximum suggestions box width relative to the textbox width. If set
- * to e.g. 2, the suggestions box will never be grown beyond 2 times the width of the textbox.
- * Type: Number, Range: 1 - infinity, Default: 3
- * expandFrom: Which direction to offset the suggestion box from.
- * Values 'start' and 'end' translate to left and right respectively depending on the
- * directionality of the current document, according to $( 'html' ).css( 'direction' ).
- * Type: String, default: 'auto', options: 'left', 'right', 'start', 'end', 'auto'.
- * positionFromLeft: Sets expandFrom=left, for backwards compatibility
- * Type: Boolean, Default: true
- * highlightInput: Whether to hightlight matched portions of the input or not
- * Type: Boolean, Default: false
+ * @class jQuery.plugin.suggestions
+ */
+/**
+ * @method suggestions
+ * @return {jQuery}
+ * @chainable
+ *
+ * @param {Object} options
+ *
+ * @param {Function} [options.fetch] Callback that should fetch suggestions and set the suggestions
+ * property. Called in context of the text box.
+ * @param {string} options.fetch.query
+ * @param {Function} options.fetch.response Callback to receive the suggestions with
+ * @param {Array} options.fetch.response.suggestions
+ * @param {number} options.fetch.maxRows
+ *
+ * @param {Function} [options.cancel] Callback function to call when any pending asynchronous
+ * suggestions fetches. Called in context of the text box.
+ *
+ * @param {Object} [options.special] Set of callbacks for rendering and selecting.
+ *
+ * @param {Function} options.special.render Called in context of the suggestions-special element.
+ * @param {string} options.special.render.query
+ * @param {Object} options.special.render.context
+ *
+ * @param {Function} options.special.select Called in context of the suggestions-result-current element.
+ * @param {jQuery} options.special.select.$textbox
+ *
+ * @param {Object} [options.result] Set of callbacks for rendering and selecting
+ *
+ * @param {Function} options.result.render Called in context of the suggestions-result element.
+ * @param {string} options.result.render.suggestion
+ * @param {Object} options.result.render.context
+ *
+ * @param {Function} options.result.select Called in context of the suggestions-result-current element.
+ * @param {jQuery} options.result.select.$textbox
+ *
+ * @param {jQuery} [options.$region=this] The element to place the suggestions below and match width of.
+ *
+ * @param {string[]} [options.suggestions] Array of suggestions to display.
+ *
+ * @param {number} [options.maxRows=10] Maximum number of suggestions to display at one time.
+ * Must be between 1 and 100.
+ *
+ * @param {number} [options.delay=120] Number of milliseconds to wait for the user to stop typing.
+ * Must be between 0 and 1200.
+ *
+ * @param {boolean} [options.cache=false] Whether to cache results from a fetch.
+ *
+ * @param {number} [options.cacheMaxAge=60000] Number of milliseconds to cache results from a fetch.
+ * Must be higher than 1. Defaults to 1 minute.
+ *
+ * @param {boolean} [options.submitOnClick=false] Whether to submit the form containing the textbox
+ * when a suggestion is clicked.
+ *
+ * @param {number} [options.maxExpandFactor=3] Maximum suggestions box width relative to the textbox
+ * width. If set to e.g. 2, the suggestions box will never be grown beyond 2 times the width of
+ * the textbox. Must be higher than 1.
+ *
+ * @param {string} [options.expandFrom=auto] Which direction to offset the suggestion box from.
+ * Values 'start' and 'end' translate to left and right respectively depending on the directionality
+ * of the current document, according to `$( 'html' ).css( 'direction' )`.
+ * Valid values: "left", "right", "start", "end", and "auto".
+ *
+ * @param {boolean} [options.positionFromLeft] Sets `expandFrom=left`, for backwards
+ * compatibility.
+ *
+ * @param {boolean} [options.highlightInput=false] Whether to hightlight matched portions of the
+ * input or not.
*/
( function ( $ ) {
var hasOwn = Object.hasOwnProperty;
+/**
+ * Used by jQuery.plugin.suggestions.
+ *
+ * @class jQuery.suggestions
+ * @singleton
+ * @private
+ */
$.suggestions = {
/**
* Cancel any delayed maybeFetch() call and callback the context so
@@ -92,7 +136,7 @@ $.suggestions = {
* call to this function still pending will be canceled. If the value in the
* textbox is empty or hasn't changed since the last time suggestions were fetched,
* this function does nothing.
- * @param {Boolean} delayed Whether or not to delay this by the currently configured amount of time
+ * @param {boolean} delayed Whether or not to delay this by the currently configured amount of time
*/
update: function ( context, delayed ) {
function maybeFetch() {
@@ -125,6 +169,7 @@ $.suggestions = {
context.data.$textbox,
val,
function ( suggestions ) {
+ suggestions = suggestions.slice( 0, context.config.maxRows );
context.data.$textbox.suggestions( 'suggestions', suggestions );
if ( context.config.cache ) {
cache[ val ] = {
@@ -132,7 +177,8 @@ $.suggestions = {
timestamp: +new Date()
};
}
- }
+ },
+ context.config.maxRows
);
}
}
@@ -167,8 +213,8 @@ $.suggestions = {
/**
* Sets the value of a property, and updates the widget accordingly
- * @param property String Name of property
- * @param value Mixed Value to set property with
+ * @param {string} property Name of property
+ * @param {Mixed} value Value to set property with
*/
configure: function ( context, property, value ) {
var newCSS,
@@ -352,8 +398,8 @@ $.suggestions = {
/**
* Highlight a result in the results table
- * @param result <tr> to highlight: jQuery object, or 'prev' or 'next'
- * @param updateTextbox If true, put the suggestion in the textbox
+ * @param {jQuery|string} result `<tr>` to highlight, or 'prev' or 'next'
+ * @param {boolean} updateTextbox If true, put the suggestion in the textbox
*/
highlight: function ( context, result, updateTextbox ) {
var selected = context.data.$container.find( '.suggestions-result-current' );
@@ -421,7 +467,7 @@ $.suggestions = {
/**
* Respond to keypress event
- * @param key Integer Code of key pressed
+ * @param {number} key Code of key pressed
*/
keypress: function ( e, context, key ) {
var selected,
@@ -474,8 +520,6 @@ $.suggestions = {
}
}
} else {
- $.suggestions.highlight( context, selected, true );
-
if ( typeof context.config.result.select === 'function' ) {
// Allow the callback to decide whether to prevent default or not
if ( context.config.result.select.call( selected, context.data.$textbox ) === true ) {
@@ -494,6 +538,8 @@ $.suggestions = {
}
}
};
+
+// See file header for method documentation
$.fn.suggestions = function () {
// Multi-context fields
@@ -503,7 +549,7 @@ $.fn.suggestions = function () {
$( this ).each( function () {
var context, key;
- /* Construction / Loading */
+ /* Construction and Loading */
context = $( this ).data( 'suggestions-context' );
if ( context === undefined || context === null ) {
@@ -515,7 +561,7 @@ $.fn.suggestions = function () {
result: {},
$region: $( this ),
suggestions: [],
- maxRows: 7,
+ maxRows: 10,
delay: 120,
cache: false,
cacheMaxAge: 60000,
@@ -681,4 +727,9 @@ $.fn.suggestions = function () {
return returnValue !== undefined ? returnValue : $( this );
};
+/**
+ * @class jQuery
+ * @mixins jQuery.plugin.suggestions
+ */
+
}( jQuery ) );
diff --git a/resources/src/jquery/jquery.tabIndex.js b/resources/src/jquery/jquery.tabIndex.js
index 46cc8f2c..ed37aa1e 100644
--- a/resources/src/jquery/jquery.tabIndex.js
+++ b/resources/src/jquery/jquery.tabIndex.js
@@ -10,8 +10,8 @@
*/
$.fn.firstTabIndex = function () {
var minTabIndex = null;
- $(this).find( '[tabindex]' ).each( function () {
- var tabIndex = parseInt( $(this).prop( 'tabindex' ), 10 );
+ $( this ).find( '[tabindex]' ).each( function () {
+ var tabIndex = parseInt( $( this ).prop( 'tabindex' ), 10 );
// In IE6/IE7 the above jQuery selector returns all elements,
// becuase it has a default value for tabIndex in IE6/IE7 of 0
// (rather than null/undefined). Therefore check "> 0" as well.
@@ -35,8 +35,8 @@
*/
$.fn.lastTabIndex = function () {
var maxTabIndex = null;
- $(this).find( '[tabindex]' ).each( function () {
- var tabIndex = parseInt( $(this).prop( 'tabindex' ), 10 );
+ $( this ).find( '[tabindex]' ).each( function () {
+ var tabIndex = parseInt( $( this ).prop( 'tabindex' ), 10 );
if ( tabIndex > 0 && !isNaN( tabIndex ) ) {
// Initial value
if ( maxTabIndex === null ) {
diff --git a/resources/src/jquery/jquery.tablesorter.js b/resources/src/jquery/jquery.tablesorter.js
index ea2c5f92..ff5ff0a9 100644
--- a/resources/src/jquery/jquery.tablesorter.js
+++ b/resources/src/jquery/jquery.tablesorter.js
@@ -15,7 +15,7 @@
*/
/**
*
- * @description Create a sortable table with multi-column sorting capabilitys
+ * @description Create a sortable table with multi-column sorting capabilities
*
* @example $( 'table' ).tablesorter();
* @desc Create a simple tablesorter interface.
@@ -35,15 +35,9 @@
* to sortable tr elements in the thead on a descending sort. Default
* value: "headerSortDown"
*
- * @option String sortInitialOrder ( optional ) A string of the inital sorting
- * order can be asc or desc. Default value: "asc"
- *
* @option String sortMultisortKey ( optional ) A string of the multi-column sort
* key. Default value: "shiftKey"
*
- * @option Boolean sortLocaleCompare ( optional ) Boolean flag indicating whatever
- * to use String.localeCampare method or not. Set to false.
- *
* @option Boolean cancelSelection ( optional ) Boolean flag indicating if
* tablesorter should cancel selection of the table headers text.
* Default value: true
@@ -53,9 +47,6 @@
* { <Integer column index>: <String 'asc' or 'desc'> }
* Default value: []
*
- * @option Boolean debug ( optional ) Boolean flag indicating if tablesorter
- * should display debuging information usefull for development.
- *
* @event sortEnd.tablesorter: Triggered as soon as any sorting has been applied.
*
* @type jQuery
@@ -192,7 +183,8 @@
var i, j, $row, cols,
totalRows = ( table.tBodies[0] && table.tBodies[0].rows.length ) || 0,
totalCells = ( table.tBodies[0].rows[0] && table.tBodies[0].rows[0].cells.length ) || 0,
- parsers = table.config.parsers,
+ config = $( table ).data( 'tablesorter' ).config,
+ parsers = config.parsers,
cache = {
row: [],
normalized: []
@@ -206,7 +198,7 @@
// if this is a child row, add it to the last row's children and
// continue to the next row
- if ( $row.hasClass( table.config.cssChildRow ) ) {
+ if ( $row.hasClass( config.cssChildRow ) ) {
cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add( $row );
// go to the next for loop
continue;
@@ -288,10 +280,12 @@
}
function buildHeaders( table, msg ) {
- var maxSeen = 0,
+ var config = $( table ).data( 'tablesorter' ).config,
+ maxSeen = 0,
colspanOffset = 0,
columns,
i,
+ $cell,
rowspan,
colspan,
headerCount,
@@ -344,30 +338,31 @@
// as each header can span over multiple columns (using colspan=N),
// we have to bidirectionally map headers to their columns and columns to their headers
- table.headerToColumns = [];
- table.columnToHeader = [];
-
$tableHeaders.each( function ( headerIndex ) {
+ $cell = $( this );
columns = [];
+
for ( i = 0; i < this.colSpan; i++ ) {
- table.columnToHeader[ colspanOffset + i ] = headerIndex;
+ config.columnToHeader[ colspanOffset + i ] = headerIndex;
columns.push( colspanOffset + i );
}
- table.headerToColumns[ headerIndex ] = columns;
+ config.headerToColumns[ headerIndex ] = columns;
colspanOffset += this.colSpan;
- this.headerIndex = headerIndex;
- this.order = 0;
- this.count = 0;
+ $cell.data( {
+ headerIndex: headerIndex,
+ order: 0,
+ count: 0
+ } );
- if ( $( this ).hasClass( table.config.unsortableClass ) ) {
- this.sortDisabled = true;
+ if ( $cell.hasClass( config.unsortableClass ) ) {
+ $cell.data( 'sortDisabled', true );
}
- if ( !this.sortDisabled ) {
- $( this )
- .addClass( table.config.cssHeader )
+ if ( !$cell.data( 'sortDisabled' ) ) {
+ $cell
+ .addClass( config.cssHeader )
.prop( 'tabIndex', 0 )
.attr( {
role: 'columnheader button',
@@ -376,7 +371,7 @@
}
// add cell to headerList
- table.config.headerList[headerIndex] = this;
+ config.headerList[headerIndex] = this;
} );
return $tableHeaders;
@@ -396,18 +391,23 @@
$.each( headerToColumns, function ( headerIndex, columns ) {
$.each( columns, function ( i, columnIndex ) {
- var header = $headers[headerIndex];
+ var header = $headers[headerIndex],
+ $header = $( header );
if ( !isValueInArray( columnIndex, sortList ) ) {
// Column shall not be sorted: Reset header count and order.
- header.order = 0;
- header.count = 0;
+ $header.data( {
+ order: 0,
+ count: 0
+ } );
} else {
// Column shall be sorted: Apply designated count and order.
$.each( sortList, function ( j, sortColumn ) {
if ( sortColumn[0] === i ) {
- header.order = sortColumn[1];
- header.count = sortColumn[1] + 1;
+ $header.data( {
+ order: sortColumn[1],
+ count: sortColumn[1] + 1
+ } );
return false;
}
} );
@@ -550,7 +550,7 @@
*/
function explodeRowspans( $table ) {
var spanningRealCellIndex, rowSpan, colSpan,
- cell, i, $tds, $clone, $nextRows,
+ cell, cellData, i, $tds, $clone, $nextRows,
rowspanCells = $table.find( '> tbody > tr > [rowspan]' ).get();
// Short circuit
@@ -566,8 +566,10 @@
col = 0,
l = this.cells.length;
for ( i = 0; i < l; i++ ) {
- this.cells[i].realCellIndex = col;
- this.cells[i].realRowIndex = this.rowIndex;
+ $( this.cells[i] ).data( 'tablesorter', {
+ realCellIndex: col,
+ realRowIndex: this.rowIndex
+ } );
col += this.cells[i].colSpan;
}
} );
@@ -577,45 +579,55 @@
// Re-sort whenever a rowspanned cell's realCellIndex is changed, because it
// might change the sort order.
function resortCells() {
+ var cellAData,
+ cellBData,
+ ret;
rowspanCells = rowspanCells.sort( function ( a, b ) {
- var ret = a.realCellIndex - b.realCellIndex;
+ cellAData = $.data( a, 'tablesorter' );
+ cellBData = $.data( b, 'tablesorter' );
+ ret = cellAData.realCellIndex - cellBData.realCellIndex;
if ( !ret ) {
- ret = a.realRowIndex - b.realRowIndex;
+ ret = cellAData.realRowIndex - cellBData.realRowIndex;
}
return ret;
} );
$.each( rowspanCells, function () {
- this.needResort = false;
+ $.data( this, 'tablesorter' ).needResort = false;
} );
}
resortCells();
function filterfunc() {
- return this.realCellIndex >= spanningRealCellIndex;
+ return $.data( this, 'tablesorter' ).realCellIndex >= spanningRealCellIndex;
}
function fixTdCellIndex() {
- this.realCellIndex += colSpan;
+ $.data( this, 'tablesorter' ).realCellIndex += colSpan;
if ( this.rowSpan > 1 ) {
- this.needResort = true;
+ $.data( this, 'tablesorter' ).needResort = true;
}
}
while ( rowspanCells.length ) {
- if ( rowspanCells[0].needResort ) {
+ if ( $.data( rowspanCells[0], 'tablesorter' ).needResort ) {
resortCells();
}
cell = rowspanCells.shift();
+ cellData = $.data( cell, 'tablesorter' );
rowSpan = cell.rowSpan;
colSpan = cell.colSpan;
- spanningRealCellIndex = cell.realCellIndex;
+ spanningRealCellIndex = cellData.realCellIndex;
cell.rowSpan = 1;
$nextRows = $( cell ).parent().nextAll();
for ( i = 0; i < rowSpan - 1; i++ ) {
$tds = $( $nextRows[i].cells ).filter( filterfunc );
$clone = $( cell ).clone();
- $clone[0].realCellIndex = spanningRealCellIndex;
+ $clone.data( 'tablesorter', {
+ realCellIndex: spanningRealCellIndex,
+ realRowIndex: cellData.realRowIndex + i,
+ needResort: true
+ } );
if ( $tds.length ) {
$tds.each( fixTdCellIndex );
$tds.first().before( $clone );
@@ -702,18 +714,14 @@
cssAsc: 'headerSortUp',
cssDesc: 'headerSortDown',
cssChildRow: 'expand-child',
- sortInitialOrder: 'asc',
sortMultiSortKey: 'shiftKey',
- sortLocaleCompare: false,
unsortableClass: 'unsortable',
parsers: {},
- widgets: [],
- headers: {},
cancelSelection: true,
sortList: [],
headerList: [],
- selectorHeaders: 'thead tr:eq(0) th',
- debug: false
+ headerToColumns: [],
+ columnToHeader: []
},
dateRegex: [],
@@ -746,17 +754,13 @@
}
$table.addClass( 'jquery-tablesorter' );
- // FIXME config should probably not be stored in the plain table node
- // New config object.
- table.config = {};
-
- // Merge and extend.
- config = $.extend( table.config, $.tablesorter.defaultOptions, settings );
+ // Merge and extend
+ config = $.extend( {}, $.tablesorter.defaultOptions, settings );
// Save the settings where they read
$.data( table, 'tablesorter', { config: config } );
- // Get the CSS class names, could be done else where.
+ // Get the CSS class names, could be done elsewhere
sortCSS = [ config.cssDesc, config.cssAsc ];
sortMsg = [ mw.msg( 'sort-descending' ), mw.msg( 'sort-ascending' ) ];
@@ -781,7 +785,7 @@
buildCollationTable();
// Legacy fix of .sortbottoms
- // Wrap them inside inside a tfoot (because that's what they actually want to be) &
+ // Wrap them inside a tfoot (because that's what they actually want to be)
// and put the <tfoot> at the end of the <table>
var $tfoot,
$sortbottoms = $table.find( '> tbody > tr.sortbottom' );
@@ -796,14 +800,14 @@
explodeRowspans( $table );
- // try to auto detect column type, and store in tables config
- table.config.parsers = buildParserCache( table, $headers );
+ // Try to auto detect column type, and store in tables config
+ config.parsers = buildParserCache( table, $headers );
}
// Apply event handling to headers
// this is too big, perhaps break it out?
- $headers.not( '.' + table.config.unsortableClass ).on( 'keypress click', function ( e ) {
- var cell, columns, newSortList, i,
+ $headers.not( '.' + config.unsortableClass ).on( 'keypress click', function ( e ) {
+ var cell, $cell, columns, newSortList, i,
totalRows,
j, s, o;
@@ -832,16 +836,21 @@
totalRows = ( $table[0].tBodies[0] && $table[0].tBodies[0].rows.length ) || 0;
if ( !table.sortDisabled && totalRows > 0 ) {
+ cell = this;
+ $cell = $( cell );
+
// Get current column sort order
- this.order = this.count % 2;
- this.count++;
+ $cell.data( {
+ order: $cell.data( 'count' ) % 2,
+ count: $cell.data( 'count' ) + 1
+ } );
cell = this;
// Get current column index
- columns = table.headerToColumns[ this.headerIndex ];
+ columns = config.headerToColumns[ $cell.data( 'headerIndex' ) ];
newSortList = $.map( columns, function ( c ) {
// jQuery "helpfully" flattens the arrays...
- return [[c, cell.order]];
+ return [[c, $cell.data( 'order' )]];
} );
// Index of first column belonging to this header
i = columns[0];
@@ -861,9 +870,8 @@
s = config.sortList[j];
o = config.headerList[s[0]];
if ( isValueInArray( s[0], newSortList ) ) {
- o.count = s[1];
- o.count++;
- s[1] = o.count % 2;
+ $( o ).data( 'count', s[1] + 1 );
+ s[1] = $( o ).data( 'count' ) % 2;
}
}
} else {
@@ -873,10 +881,10 @@
}
// Reset order/counts of cells not affected by sorting
- setHeadersOrder( $headers, config.sortList, table.headerToColumns );
+ setHeadersOrder( $headers, config.sortList, config.headerToColumns );
// Set CSS for headers
- setHeadersCss( $table[0], $headers, config.sortList, sortCSS, sortMsg, table.columnToHeader );
+ setHeadersCss( $table[0], $headers, config.sortList, sortCSS, sortMsg, config.columnToHeader );
appendToTable(
$table[0], multisort( $table[0], config.sortList, cache )
);
@@ -917,13 +925,13 @@
// Set each column's sort count to be able to determine the correct sort
// order when clicking on a header cell the next time
- setHeadersOrder( $headers, sortList, table.headerToColumns );
+ setHeadersOrder( $headers, sortList, config.headerToColumns );
// re-build the cache for the tbody cells
cache = buildCache( table );
// set css for headers
- setHeadersCss( table, $headers, sortList, sortCSS, sortMsg, table.columnToHeader );
+ setHeadersCss( table, $headers, sortList, sortCSS, sortMsg, config.columnToHeader );
// sort the table and append it to the dom
appendToTable( table, multisort( table, sortList, cache ) );
@@ -983,6 +991,15 @@
clearTableBody: function ( table ) {
$( table.tBodies[0] ).empty();
+ },
+
+ getParser: function ( id ) {
+ buildTransformTable();
+ buildDateTable();
+ cacheRegexs();
+ buildCollationTable();
+
+ return getParserById( id );
}
};
@@ -1104,9 +1121,9 @@
return '99999999';
}
} else if ( ( match = s.match( ts.dateRegex[1] ) ) !== null ) {
- s = [ match[3], '' + ts.monthNames[match[2]], match[1] ];
+ s = [ match[3], String( ts.monthNames[match[2]] ), match[1] ];
} else if ( ( match = s.match( ts.dateRegex[2] ) ) !== null ) {
- s = [ match[3], '' + ts.monthNames[match[1]], match[2] ];
+ s = [ match[3], String( ts.monthNames[match[1]] ), match[2] ];
} else {
// Should never get here
return '99999999';
diff --git a/resources/src/jquery/jquery.textSelection.js b/resources/src/jquery/jquery.textSelection.js
index 8d440fdc..51119305 100644
--- a/resources/src/jquery/jquery.textSelection.js
+++ b/resources/src/jquery/jquery.textSelection.js
@@ -24,8 +24,9 @@
$.fn.textSelection = function ( command, options ) {
var fn,
+ alternateFn,
context,
- hasWikiEditorSurface, // The alt edit surface needs to implement the WikiEditor API
+ hasWikiEditor,
needSave,
retval;
@@ -210,9 +211,10 @@
endPos = this.selectionEnd;
scrollTop = this.scrollTop;
checkSelectedText();
- if ( options.selectionStart !== undefined
- && endPos - startPos !== options.selectionEnd - options.selectionStart )
- {
+ if (
+ options.selectionStart !== undefined &&
+ endPos - startPos !== options.selectionEnd - options.selectionStart
+ ) {
// This means there is a difference in the selection range returned by browser and what we passed.
// This happens for Chrome in the case of composite characters. Ref bug #30130
// Set the startPos to the correct position.
@@ -242,7 +244,7 @@
selText = selText.replace( /\r?\n/g, '\r\n' );
post = post.replace( /\r?\n/g, '\r\n' );
}
- if ( isSample && options.selectPeri && !options.splitlines ) {
+ if ( isSample && options.selectPeri && ( !options.splitlines || ( options.splitlines && selText.indexOf( '\n' ) === -1 ) ) ) {
this.selectionStart = startPos + pre.length;
this.selectionEnd = startPos + pre.length + selText.length;
} else {
@@ -507,11 +509,13 @@
}
};
+ alternateFn = $( this ).data( 'jquery.textSelection' );
+
// Apply defaults
switch ( command ) {
- //case 'getContents': // no params
- //case 'setContents': // no params with defaults
- //case 'getSelection': // no params
+ // case 'getContents': // no params
+ // case 'setContents': // no params with defaults
+ // case 'getSelection': // no params
case 'encapsulateSelection':
options = $.extend( {
pre: '', // Text to insert before the cursor/selection
@@ -550,19 +554,30 @@
force: false // Force a scroll even if the caret position is already visible
}, options );
break;
+ case 'register':
+ if ( alternateFn ) {
+ throw new Error( 'Another textSelection API was already registered' );
+ }
+ $( this ).data( 'jquery.textSelection', options );
+ // No need to update alternateFn as this command only stores the options.
+ // A command that uses it will set it again.
+ return;
+ case 'unregister':
+ $( this ).removeData( 'jquery.textSelection' );
+ return;
}
context = $( this ).data( 'wikiEditor-context' );
- hasWikiEditorSurface = ( context !== undefined && context.$iframe !== undefined );
+ hasWikiEditor = ( context !== undefined && context.$iframe !== undefined );
// IE selection restore voodoo
needSave = false;
- if ( hasWikiEditorSurface && context.savedSelection !== null ) {
+ if ( hasWikiEditor && context.savedSelection !== null ) {
context.fn.restoreSelection();
needSave = true;
}
- retval = ( hasWikiEditorSurface && context.fn[command] !== undefined ? context.fn : fn )[command].call( this, options );
- if ( hasWikiEditorSurface && needSave ) {
+ retval = ( alternateFn && alternateFn[command] || fn[command] ).call( this, options );
+ if ( hasWikiEditor && needSave ) {
context.fn.saveSelection();
}
diff --git a/resources/src/mediawiki.action/images/nextredirect-ltr.png b/resources/src/mediawiki.action/images/nextredirect-ltr.png
index cd657c33..e0a6bd7f 100644
--- a/resources/src/mediawiki.action/images/nextredirect-ltr.png
+++ b/resources/src/mediawiki.action/images/nextredirect-ltr.png
Binary files differ
diff --git a/resources/src/mediawiki.action/images/nextredirect-ltr.svg b/resources/src/mediawiki.action/images/nextredirect-ltr.svg
new file mode 100644
index 00000000..6932e580
--- /dev/null
+++ b/resources/src/mediawiki.action/images/nextredirect-ltr.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="42" height="20" viewBox="0 0 42 20">
+ <g id="Layer_2">
+ <path fill="#fff" stroke="#000" stroke-width="2" stroke-miterlimit="10" d="M11 10h17.064"/>
+ </g>
+ <g id="Layer_3">
+ <path d="M23 6l8 4-8 4z"/>
+ </g>
+</svg>
diff --git a/resources/src/mediawiki.action/images/nextredirect-rtl.png b/resources/src/mediawiki.action/images/nextredirect-rtl.png
index b788f334..ddb5273b 100644
--- a/resources/src/mediawiki.action/images/nextredirect-rtl.png
+++ b/resources/src/mediawiki.action/images/nextredirect-rtl.png
Binary files differ
diff --git a/resources/src/mediawiki.action/images/nextredirect-rtl.svg b/resources/src/mediawiki.action/images/nextredirect-rtl.svg
new file mode 100644
index 00000000..b309da94
--- /dev/null
+++ b/resources/src/mediawiki.action/images/nextredirect-rtl.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="42" height="20" viewBox="0 0 42 20">
+ <g id="Layer_2">
+ <path fill="#fff" stroke="#000" stroke-width="2" stroke-miterlimit="10" d="M31 10H13.936"/>
+ </g>
+ <g id="Layer_3">
+ <path d="M19 6l-8 4 8 4z"/>
+ </g>
+</svg>
diff --git a/resources/src/mediawiki.action/images/redirect-ltr.png b/resources/src/mediawiki.action/images/redirect-ltr.png
index 695f2a13..0734d731 100644
--- a/resources/src/mediawiki.action/images/redirect-ltr.png
+++ b/resources/src/mediawiki.action/images/redirect-ltr.png
Binary files differ
diff --git a/resources/src/mediawiki.action/images/redirect-ltr.svg b/resources/src/mediawiki.action/images/redirect-ltr.svg
new file mode 100644
index 00000000..713be6cb
--- /dev/null
+++ b/resources/src/mediawiki.action/images/redirect-ltr.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="47" height="20" viewBox="0 0 47 20">
+ <g id="Layer_1">
+ <path fill="none" stroke="#000" stroke-width="2" stroke-miterlimit="10" d="M14.98 2.5V11c0 1.04 1.02 1.98 2.02 1.98h6l3 .02"/>
+ </g>
+ <g id="Layer_3">
+ <path d="M23.48 9.5l.02 7L30 13z"/>
+ </g>
+</svg>
diff --git a/resources/src/mediawiki.action/images/redirect-rtl.png b/resources/src/mediawiki.action/images/redirect-rtl.png
index c954a2ad..c883795e 100644
--- a/resources/src/mediawiki.action/images/redirect-rtl.png
+++ b/resources/src/mediawiki.action/images/redirect-rtl.png
Binary files differ
diff --git a/resources/src/mediawiki.action/images/redirect-rtl.svg b/resources/src/mediawiki.action/images/redirect-rtl.svg
new file mode 100644
index 00000000..ce0c7c92
--- /dev/null
+++ b/resources/src/mediawiki.action/images/redirect-rtl.svg
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="47" height="20" viewBox="0 0 47 20">
+ <g id="Layer_1">
+ <path fill="none" stroke="#000" stroke-width="2" stroke-miterlimit="10" d="M32.002 2.5V11c0 1.04-1.02 1.98-2.02 1.98h-6l-3 .02"/>
+ </g>
+ <g id="Layer_3">
+ <path d="M23.502 9.5l-.02 7-6.5-3.5z"/>
+ </g>
+</svg>
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js b/resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js
index b5654400..6b330128 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js
@@ -5,54 +5,37 @@
'use strict';
$( function () {
- var savedWindowOnBeforeUnload,
- $wpTextbox1 = $( '#wpTextbox1' ),
- $wpSummary = $( '#wpSummary' );
+ var allowCloseWindow,
+ $textBox = $( '#wpTextbox1' ),
+ $summary = $( '#wpSummary' ),
+ $both = $textBox.add( $summary );
+
// Check if EditWarning is enabled and if we need it
- if ( $wpTextbox1.length === 0 ) {
+ if ( !mw.user.options.get( 'useeditwarning' ) ) {
return true;
}
- // Get the original values of some form elements
- $wpTextbox1.add( $wpSummary ).each( function () {
- $( this ).data( 'origtext', $( this ).val() );
+
+ // Save the original value of the text fields
+ $both.each( function ( index, element ) {
+ var $element = $( element );
+ $element.data( 'origtext', $element.textSelection( 'getContents' ) );
} );
- $( window )
- .on( 'beforeunload.editwarning', function () {
- var retval;
- // Check if the current values of some form elements are the same as
- // the original values
- if (
- mw.config.get( 'wgAction' ) === 'submit' ||
- $wpTextbox1.data( 'origtext' ) !== $wpTextbox1.textSelection( 'getContents' ) ||
- $wpSummary.data( 'origtext' ) !== $wpSummary.textSelection( 'getContents' )
- ) {
- // Return our message
- retval = mw.msg( 'editwarning-warning' );
- }
+ allowCloseWindow = mw.confirmCloseWindow( {
+ test: function () {
+ // We use .textSelection, because editors might not have updated the form yet.
+ return mw.config.get( 'wgAction' ) === 'submit' ||
+ $textBox.data( 'origtext' ) !== $textBox.textSelection( 'getContents' ) ||
+ $summary.data( 'origtext' ) !== $summary.textSelection( 'getContents' );
+ },
- // Unset the onbeforeunload handler so we don't break page caching in Firefox
- savedWindowOnBeforeUnload = window.onbeforeunload;
- window.onbeforeunload = null;
- if ( retval !== undefined ) {
- // ...but if the user chooses not to leave the page, we need to rebind it
- setTimeout( function () {
- window.onbeforeunload = savedWindowOnBeforeUnload;
- }, 1 );
- return retval;
- }
- } )
- .on( 'pageshow.editwarning', function () {
- // Re-add onbeforeunload handler
- if ( !window.onbeforeunload ) {
- window.onbeforeunload = savedWindowOnBeforeUnload;
- }
- } );
+ message: mw.msg( 'editwarning-warning' ),
+ namespace: 'editwarning'
+ } );
// Add form submission handler
$( '#editform' ).submit( function () {
- // Unbind our handlers
- $( window ).off( '.editwarning' );
+ allowCloseWindow();
} );
} );
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.js b/resources/src/mediawiki.action/mediawiki.action.edit.js
index 4519b049..01a25f3b 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.js
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.js
@@ -1,217 +1,23 @@
-/**
- * Interface for the classic edit toolbar.
- *
- * @class mw.toolbar
- * @singleton
+/*!
+ * Scripts for action=edit at domready
*/
-( function ( mw, $ ) {
- var toolbar, isReady, $toolbar, queue, slice, $currentFocused;
-
- /**
- * Internal helper that does the actual insertion of the button into the toolbar.
- *
- * See #addButton for parameter documentation.
- *
- * @private
- */
- function insertButton( b, speedTip, tagOpen, tagClose, sampleText, imageId ) {
- var $button;
-
- // Backwards compatibility
- if ( typeof b !== 'object' ) {
- b = {
- imageFile: b,
- speedTip: speedTip,
- tagOpen: tagOpen,
- tagClose: tagClose,
- sampleText: sampleText,
- imageId: imageId
- };
- }
-
- if ( b.imageFile ) {
- $button = $( '<img>' ).attr( {
- src: b.imageFile,
- alt: b.speedTip,
- title: b.speedTip,
- id: b.imageId || undefined,
- 'class': 'mw-toolbar-editbutton'
- } );
- } else {
- $button = $( '<div>' ).attr( {
- title: b.speedTip,
- id: b.imageId || undefined,
- 'class': 'mw-toolbar-editbutton'
- } );
+jQuery( function ( $ ) {
+ var editBox, scrollTop, $editForm;
+
+ // Make sure edit summary does not exceed byte limit
+ $( '#wpSummary' ).byteLimit( 255 );
+
+ // Restore the edit box scroll state following a preview operation,
+ // and set up a form submission handler to remember this state.
+ editBox = document.getElementById( 'wpTextbox1' );
+ scrollTop = document.getElementById( 'wpScrolltop' );
+ $editForm = $( '#editform' );
+ if ( $editForm.length && editBox && scrollTop ) {
+ if ( scrollTop.value ) {
+ editBox.scrollTop = scrollTop.value;
}
-
- $button.click( function ( e ) {
- if ( b.onClick !== undefined ) {
- b.onClick( e );
- } else {
- toolbar.insertTags( b.tagOpen, b.tagClose, b.sampleText );
- }
-
- return false;
+ $editForm.submit( function () {
+ scrollTop.value = editBox.scrollTop;
} );
-
- $toolbar.append( $button );
}
-
- isReady = false;
- $toolbar = false;
-
- /**
- * @private
- * @property {Array}
- * Contains button objects (and for backwards compatibilty, it can
- * also contains an arguments array for insertButton).
- */
- queue = [];
- slice = queue.slice;
-
- toolbar = {
-
- /**
- * Add buttons to the toolbar.
- *
- * Takes care of race conditions and time-based dependencies
- * by placing buttons in a queue if this method is called before
- * the toolbar is created.
- *
- * For backwards-compatibility, passing `imageFile`, `speedTip`, `tagOpen`, `tagClose`,
- * `sampleText` and `imageId` as separate arguments (in this order) is also supported.
- *
- * @param {Object} button Object with the following properties.
- * You are required to provide *either* the `onClick` parameter, or the three parameters
- * `tagOpen`, `tagClose` and `sampleText`, but not both (they're mutually exclusive).
- * @param {string} [button.imageFile] Image to use for the button.
- * @param {string} button.speedTip Tooltip displayed when user mouses over the button.
- * @param {Function} [button.onClick] Function to be executed when the button is clicked.
- * @param {string} [button.tagOpen]
- * @param {string} [button.tagClose]
- * @param {string} [button.sampleText] Alternative to `onClick`. `tagOpen`, `tagClose` and
- * `sampleText` together provide the markup that should be inserted into page text at
- * current cursor position.
- * @param {string} [button.imageId] `id` attribute of the button HTML element. Can be
- * used to define the image with CSS if it's not provided as `imageFile`.
- */
- addButton: function () {
- if ( isReady ) {
- insertButton.apply( toolbar, arguments );
- } else {
- // Convert arguments list to array
- queue.push( slice.call( arguments ) );
- }
- },
- /**
- * Add multiple buttons to the toolbar (see also #addButton).
- *
- * Example usage:
- *
- * addButtons( [ { .. }, { .. }, { .. } ] );
- * addButtons( { .. }, { .. } );
- *
- * @param {Object|Array...} [buttons] An array of button objects or the first
- * button object in a list of variadic arguments.
- */
- addButtons: function ( buttons ) {
- if ( !$.isArray( buttons ) ) {
- buttons = slice.call( arguments );
- }
- if ( isReady ) {
- $.each( buttons, function () {
- insertButton( this );
- } );
- } else {
- // Push each button into the queue
- queue.push.apply( queue, buttons );
- }
- },
-
- /**
- * Apply tagOpen/tagClose to selection in currently focused textarea.
- *
- * Uses `sampleText` if selection is empty.
- *
- * @param {string} tagOpen
- * @param {string} tagClose
- * @param {string} sampleText
- */
- insertTags: function ( tagOpen, tagClose, sampleText ) {
- if ( $currentFocused && $currentFocused.length ) {
- $currentFocused.textSelection(
- 'encapsulateSelection', {
- pre: tagOpen,
- peri: sampleText,
- post: tagClose
- }
- );
- }
- },
-
- // For backwards compatibility,
- // Called from EditPage.php, maybe in other places as well.
- init: function () {}
- };
-
- // Legacy (for compatibility with the code previously in skins/common.edit.js)
- mw.log.deprecate( window, 'addButton', toolbar.addButton, 'Use mw.toolbar.addButton instead.' );
- mw.log.deprecate( window, 'insertTags', toolbar.insertTags, 'Use mw.toolbar.insertTags instead.' );
-
- // Expose API publicly
- mw.toolbar = toolbar;
-
- $( function () {
- var i, b, editBox, scrollTop, $editForm;
-
- // Used to determine where to insert tags
- $currentFocused = $( '#wpTextbox1' );
-
- // Populate the selector cache for $toolbar
- $toolbar = $( '#toolbar' );
-
- for ( i = 0; i < queue.length; i++ ) {
- b = queue[i];
- if ( $.isArray( b ) ) {
- // Forwarded arguments array from mw.toolbar.addButton
- insertButton.apply( toolbar, b );
- } else {
- // Raw object from mw.toolbar.addButtons
- insertButton( b );
- }
- }
-
- // Clear queue
- queue.length = 0;
-
- // This causes further calls to addButton to go to insertion directly
- // instead of to the queue.
- // It is important that this is after the one and only loop through
- // the the queue
- isReady = true;
-
- // Make sure edit summary does not exceed byte limit
- $( '#wpSummary' ).byteLimit( 255 );
-
- // Restore the edit box scroll state following a preview operation,
- // and set up a form submission handler to remember this state.
- editBox = document.getElementById( 'wpTextbox1' );
- scrollTop = document.getElementById( 'wpScrolltop' );
- $editForm = $( '#editform' );
- if ( $editForm.length && editBox && scrollTop ) {
- if ( scrollTop.value ) {
- editBox.scrollTop = scrollTop.value;
- }
- $editForm.submit( function () {
- scrollTop.value = editBox.scrollTop;
- } );
- }
-
- // Apply to dynamically created textboxes as well as normal ones
- $( document ).on( 'focus', 'textarea, input:text', function () {
- $currentFocused = $( this );
- } );
- } );
-
-}( mediaWiki, jQuery ) );
+} );
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.preview.js b/resources/src/mediawiki.action/mediawiki.action.edit.preview.js
index 6b212c28..f24703af 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.preview.js
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.preview.js
@@ -8,17 +8,29 @@
* @param {jQuery.Event} e
*/
function doLivePreview( e ) {
- var $wikiPreview, $editform, copySelectors, $copyElements, $spinner,
- targetUrl, postData, $previewDataHolder;
-
- e.preventDefault();
-
- // Deprecated: Use mw.hook instead
- $( mw ).trigger( 'LivePreviewPrepare' );
+ var isDiff, api, request, postData, copySelectors, section,
+ $wikiPreview, $wikiDiff, $editform, $textbox, $summary, $copyElements, $spinner, $errorBox;
+ isDiff = ( e.target.name === 'wpDiff' );
$wikiPreview = $( '#wikiPreview' );
+ $wikiDiff = $( '#wikiDiff' );
$editform = $( '#editform' );
+ $textbox = $editform.find( '#wpTextbox1' );
+ $summary = $editform.find( '#wpSummary' );
+ $errorBox = $( '.errorbox' );
+ section = $editform.find( '[name="wpSection"]' ).val();
+
+ if ( $textbox.length === 0 ) {
+ return;
+ }
+ // Show changes for a new section is not yet supported
+ if ( isDiff && section === 'new' ) {
+ return;
+ }
+ e.preventDefault();
+ // Remove any previously displayed errors
+ $errorBox.remove();
// Show #wikiPreview if it's hidden to be able to scroll to it
// (if it is hidden, it's also empty, so nothing changes in the rendering)
$wikiPreview.show();
@@ -26,15 +38,12 @@
// Jump to where the preview will appear
$wikiPreview[0].scrollIntoView();
- // List of selectors matching elements that we will
- // update from from the ajax-loaded preview page.
copySelectors = [
// Main
'#firstHeading',
'#wikiPreview',
'#wikiDiff',
'#catlinks',
- '.hiddencats',
'#p-lang',
// Editing-related
'.templatesUsed',
@@ -59,70 +68,184 @@
// (e.g. empty #catlinks)
$copyElements.animate( { opacity: 0.4 }, 'fast' );
- $previewDataHolder = $( '<div>' );
- targetUrl = $editform.attr( 'action' );
- targetUrl += targetUrl.indexOf( '?' ) !== -1 ? '&' : '?';
- targetUrl += $.param( {
- debug: mw.config.get( 'debug' ),
+ api = new mw.Api();
+ postData = {
+ action: 'parse',
uselang: mw.config.get( 'wgUserLanguage' ),
- useskin: mw.config.get( 'skin' )
- } );
+ title: mw.config.get( 'wgPageName' ),
+ text: $textbox.textSelection( 'getContents' ),
+ summary: $summary.textSelection( 'getContents' )
+ };
- // Gather all the data from the form
- postData = $editform.formToArray();
- postData.push( {
- name: e.target.name,
- value: ''
- } );
+ if ( section !== '' ) {
+ postData.sectionpreview = '';
+ if ( section === 'new' ) {
+ postData.section = section;
+ postData.sectiontitle = postData.summary;
+ }
+ }
- // Load new preview data.
- // TODO: This should use the action=parse API instead of loading the entire page,
- // although that requires figuring out how to convert that raw data into proper HTML.
- $previewDataHolder.load( targetUrl + ' ' + copySelectors.join( ',' ), postData, function () {
- var i, $from, $next, $parent;
+ if ( isDiff ) {
+ $wikiPreview.hide();
- // Copy the contents of the specified elements from the loaded page to the real page.
- // Also copy their class attributes.
- for ( i = 0; i < copySelectors.length; i++ ) {
- $from = $previewDataHolder.find( copySelectors[i] );
+ // First PST the input, then diff it
+ postData.onlypst = '';
+ request = api.post( postData );
+ request.done( function ( response ) {
+ var postData;
+ postData = {
+ action: 'query',
+ indexpageids: '',
+ prop: 'revisions',
+ titles: mw.config.get( 'wgPageName' ),
+ rvdifftotext: response.parse.text['*'],
+ rvprop: ''
+ };
+ if ( section !== '' ) {
+ postData.rvsection = section;
+ }
+ return api.post( postData ).done( function ( result2 ) {
+ try {
+ var diffHtml = result2.query.pages[result2.query.pageids[0]]
+ .revisions[0].diff['*'];
+ $wikiDiff.find( 'table.diff tbody' ).html( diffHtml );
+ } catch ( e ) {
+ // "result.blah is undefined" error, ignore
+ mw.log.warn( e );
+ }
+ $wikiDiff.show();
+ } );
+ } );
+ } else {
+ $wikiDiff.hide();
+ $.extend( postData, {
+ pst: '',
+ preview: '',
+ prop: 'text|displaytitle|modules|categorieshtml|templates|langlinks|limitreporthtml',
+ disableeditsection: true
+ } );
+ request = api.post( postData );
+ request.done( function ( response ) {
+ var li, newList, $displaytitle, $content, $parent, $list;
+ if ( response.parse.modules ) {
+ mw.loader.load( response.parse.modules.concat(
+ response.parse.modulescripts,
+ response.parse.modulestyles,
+ response.parse.modulemessages ) );
+ }
+ if ( response.parse.displaytitle ) {
+ $displaytitle = $( $.parseHTML( response.parse.displaytitle ) );
+ $( '#firstHeading' ).msg(
+ mw.config.get( 'wgEditMessage', 'editing' ),
+ $displaytitle
+ );
+ document.title = mw.msg(
+ 'pagetitle',
+ mw.msg(
+ mw.config.get( 'wgEditMessage', 'editing' ),
+ $displaytitle.text()
+ )
+ );
+ }
+ if ( response.parse.categorieshtml ) {
+ $( '#catlinks' ).replaceWith( response.parse.categorieshtml['*'] );
+ }
+ if ( response.parse.templates ) {
+ newList = [];
+ $.each( response.parse.templates, function ( i, template ) {
+ li = $( '<li>' )
+ .append( $( '<a>' )
+ .attr( {
+ 'href': mw.util.getUrl( template['*'] ),
+ 'class': ( template.exists !== undefined ? '' : 'new' )
+ } )
+ .text( template['*'] )
+ );
+ newList.push( li );
+ } );
- if ( copySelectors[i] === '#wikiPreview' ) {
- $next = $wikiPreview.next();
- // If there is no next node, use parent instead.
- // Only query parent if needed, false otherwise.
- $parent = !$next.length && $wikiPreview.parent();
+ $editform.find( '.templatesUsed .mw-editfooter-list' ).detach().empty().append( newList ).appendTo( '.templatesUsed' );
+ }
+ if ( response.parse.limitreporthtml ) {
+ $( '.limitreport' ).html( response.parse.limitreporthtml['*'] );
+ }
+ if ( response.parse.langlinks && mw.config.get( 'skin' ) === 'vector' ) {
+ newList = [];
+ $.each( response.parse.langlinks, function ( i, langlink ) {
+ li = $( '<li>' )
+ .addClass( 'interlanguage-link interwiki-' + langlink.lang )
+ .append( $( '<a>' )
+ .attr( {
+ 'href': langlink.url,
+ 'title': langlink['*'] + ' - ' + langlink.langname,
+ 'lang': langlink.lang,
+ 'hreflang': langlink.lang
+ } )
+ .text( langlink.autonym )
+ );
+ newList.push( li );
+ } );
+ $list = $( '#p-lang ul' );
+ $parent = $list.parent();
+ $list.detach().empty().append( newList ).prependTo( $parent );
+ }
- $wikiPreview
+ if ( response.parse.text['*'] ) {
+ $content = $wikiPreview.children( '.mw-content-ltr,.mw-content-rtl' );
+ $content
.detach()
- .empty()
- .append( $from.contents() )
- .attr( 'class', $from.attr( 'class' ) );
+ .html( response.parse.text['*'] );
- mw.hook( 'wikipage.content' ).fire( $wikiPreview );
+ mw.hook( 'wikipage.content' ).fire( $content );
// Reattach
- if ( $parent ) {
- $parent.append( $wikiPreview );
- } else {
- $next.before( $wikiPreview );
- }
+ $wikiPreview.append( $content );
+
+ $wikiPreview.show();
- } else {
- $( copySelectors[i] )
- .empty()
- .append( $from.contents() )
- .attr( 'class', $from.attr( 'class' ) );
}
+ } );
+ }
+ request.done( function ( response ) {
+ var isSubject = ( section === 'new' ),
+ summaryMsg = isSubject ? 'subject-preview' : 'summary-preview';
+ if ( response.parse.parsedsummary ) {
+ $editform.find( '.mw-summary-preview' )
+ .empty()
+ .append(
+ mw.message( summaryMsg ).parse(),
+ ' ',
+ $( '<span>' ).addClass( 'comment' ).html(
+ // There is no equivalent to rawParams
+ mw.message( 'parentheses' ).escaped()
+ .replace( '$1', response.parse.parsedsummary['*'] )
+ )
+ );
}
-
- // Deprecated: Use mw.hook instead
- $( mw ).trigger( 'LivePreviewDone', [copySelectors] );
-
+ } );
+ request.always( function () {
$spinner.remove();
$copyElements.animate( {
opacity: 1
}, 'fast' );
} );
+ request.fail( function ( code, result ) {
+ var errorMsg = 'API error: ' + code;
+ if ( code === 'http' ) {
+ errorMsg = 'HTTP error: ';
+ if ( result.exception ) {
+ errorMsg += result.exception;
+ } else {
+ errorMsg += result.textStatus;
+ }
+ }
+ $errorBox = $( '<div>' )
+ .addClass( 'errorbox' )
+ .html( '<strong>' + mw.message( 'previewerrortext' ).escaped() + '</strong><br>' )
+ .append( document.createTextNode( errorMsg ) );
+ $wikiDiff.hide();
+ $wikiPreview.hide().before( $errorBox );
+ } );
}
$( function () {
@@ -138,21 +261,33 @@
// have to fish and (hopefully) put them in the right place (since skins
// can change where they are output).
- if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) ) {
- $( '#p-tb' ).after(
- $( '<div>' ).attr( 'id', 'p-lang' )
+ if ( !document.getElementById( 'p-lang' ) && document.getElementById( 'p-tb' ) && mw.config.get( 'skin' ) === 'vector' ) {
+ $( '.portal:last' ).after(
+ $( '<div>' ).attr( {
+ 'class': 'portal',
+ 'id': 'p-lang',
+ 'role': 'navigation',
+ 'title': mw.msg( 'tooltip-p-lang' ),
+ 'aria-labelledby': 'p-lang-label'
+ } )
+ .append( $( '<h3>' ).attr( 'id', 'p-lang-label' ).text( mw.msg( 'otherlanguages' ) ) )
+ .append( $( '<div>' ).addClass( 'body' ).append( '<ul>' ) )
);
}
if ( !$( '.mw-summary-preview' ).length ) {
- $( '.editCheckboxes' ).before(
+ $( '#wpSummary' ).after(
$( '<div>' ).addClass( 'mw-summary-preview' )
);
}
if ( !document.getElementById( 'wikiDiff' ) && document.getElementById( 'wikiPreview' ) ) {
$( '#wikiPreview' ).after(
- $( '<div>' ).attr( 'id', 'wikiDiff' )
+ $( '<div>' )
+ .hide()
+ .attr( 'id', 'wikiDiff' )
+ .html( '<table class="diff"><col class="diff-marker"/><col class="diff-content"/>' +
+ '<col class="diff-marker"/><col class="diff-content"/><tbody/></table>' )
);
}
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.stash.js b/resources/src/mediawiki.action/mediawiki.action.edit.stash.js
new file mode 100644
index 00000000..29c533d8
--- /dev/null
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.stash.js
@@ -0,0 +1,76 @@
+/*!
+ * Scripts for pre-emptive edit preparing on action=edit
+ */
+( function ( mw, $ ) {
+ $( function () {
+ var idleTimeout = 4000,
+ api = new mw.Api(),
+ pending = null,
+ $form = $( '#editform' ),
+ $text = $form.find( '#wpTextbox1' ),
+ data = {},
+ timer = null;
+
+ function stashEdit( token ) {
+ data = $form.serializeObject();
+
+ pending = api.post( {
+ action: 'stashedit',
+ token: token,
+ title: mw.config.get( 'wgPageName' ),
+ section: data.wpSection,
+ sectiontitle: '',
+ text: data.wpTextbox1,
+ contentmodel: data.model,
+ contentformat: data.format,
+ baserevid: data.parentRevId
+ } );
+ }
+
+ /* Has the edit body text changed since the last stashEdit() call? */
+ function isChanged() {
+ // Normalize line endings to CRLF, like $.fn.serializeObject does.
+ var newText = $text.val().replace( /\r?\n/g, '\r\n' );
+ return newText !== data.wpTextbox1;
+ }
+
+ function onEditChanged() {
+ if ( !isChanged() ) {
+ return;
+ }
+
+ // If a request is in progress, abort it; its payload is stale.
+ if ( pending ) {
+ pending.abort();
+ }
+
+ api.getToken( 'edit' ).then( stashEdit );
+ }
+
+ function onKeyPress( e ) {
+ // Ignore keystrokes that don't modify text, like cursor movements.
+ // See <http://stackoverflow.com/q/2284844>.
+ if ( e.which === 0 ) {
+ return;
+ }
+
+ clearTimeout( timer );
+
+ if ( pending ) {
+ pending.abort();
+ }
+
+ timer = setTimeout( onEditChanged, idleTimeout );
+ }
+
+ // We don't attempt to stash new section edits because in such cases
+ // the parser output varies on the edit summary (since it determines
+ // the new section's name).
+ if ( $form.find( 'input[name=wpSection]' ).val() === 'new' ) {
+ return;
+ }
+
+ $text.on( { change: onEditChanged, keypress: onKeyPress } );
+
+ } );
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.styles.css b/resources/src/mediawiki.action/mediawiki.action.edit.styles.css
index 7148b964..4209aa1f 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.styles.css
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.styles.css
@@ -8,14 +8,6 @@
display: block;
}
-.editOptions {
- background-color: #F0F0F0;
- border: 1px solid silver;
- border-top: none;
- padding: 1em 1em 1.5em 1em;
- margin-bottom: 2em;
-}
-
/* Adjustments to edit form elements */
.editCheckboxes {
margin-bottom: 1em;
diff --git a/resources/src/mediawiki.action/mediawiki.action.history.diff.css b/resources/src/mediawiki.action/mediawiki.action.history.diff.css
index afe92468..0887476e 100644
--- a/resources/src/mediawiki.action/mediawiki.action.history.diff.css
+++ b/resources/src/mediawiki.action/mediawiki.action.history.diff.css
@@ -1,8 +1,7 @@
-/*
-** Diff rendering
-*/
+/*!
+ * Diff rendering
+ */
table.diff {
- background-color: white;
border: none;
border-spacing: 4px;
margin: 0;
diff --git a/resources/src/mediawiki.action/mediawiki.action.history.diff.print.css b/resources/src/mediawiki.action/mediawiki.action.history.diff.print.css
new file mode 100644
index 00000000..76b5c9b7
--- /dev/null
+++ b/resources/src/mediawiki.action/mediawiki.action.history.diff.print.css
@@ -0,0 +1,16 @@
+/*!
+ * Diff rendering
+ */
+td.diff-context,
+td.diff-addedline .diffchange,
+td.diff-deletedline .diffchange {
+ background-color: transparent;
+}
+
+td.diff-addedline .diffchange {
+ text-decoration: underline;
+}
+
+td.diff-deletedline .diffchange {
+ text-decoration: line-through;
+}
diff --git a/resources/src/mediawiki.action/mediawiki.action.history.js b/resources/src/mediawiki.action/mediawiki.action.history.js
index ac48c596..2ebfe921 100644
--- a/resources/src/mediawiki.action/mediawiki.action.history.js
+++ b/resources/src/mediawiki.action/mediawiki.action.history.js
@@ -85,7 +85,8 @@ jQuery( function ( $ ) {
$copyForm.find( 'input[name^="ids["]:checked' ).prop( 'checked', false );
// Remove diff=&oldid=, change action=historysubmit to revisiondelete, remove revisiondelete
- } else if ( $historySubmitter.hasClass( 'mw-history-revisiondelete-button' ) ) {
+ } else if ( $historySubmitter.hasClass( 'mw-history-revisiondelete-button' ) ||
+ $historySubmitter.hasClass( 'mw-history-editchangetags-button' ) ) {
$copyRadios.remove();
$copyAction.val( $historySubmitter.attr( 'name' ) );
$copyForm.find( ':submit' ).remove();
diff --git a/resources/src/mediawiki.action/mediawiki.action.view.categoryPage.less b/resources/src/mediawiki.action/mediawiki.action.view.categoryPage.less
new file mode 100644
index 00000000..387b0207
--- /dev/null
+++ b/resources/src/mediawiki.action/mediawiki.action.view.categoryPage.less
@@ -0,0 +1,11 @@
+@import "mediawiki.mixins";
+
+.mw-category {
+ .column-count(3);
+ .column-width(24em);
+ .mw-category-group {
+ li {
+ .column-break-inside-avoid;
+ }
+ }
+}
diff --git a/resources/src/mediawiki.action/mediawiki.action.view.dblClickEdit.js b/resources/src/mediawiki.action/mediawiki.action.view.dblClickEdit.js
index 2ded40cf..2be29f09 100644
--- a/resources/src/mediawiki.action/mediawiki.action.view.dblClickEdit.js
+++ b/resources/src/mediawiki.action/mediawiki.action.view.dblClickEdit.js
@@ -4,9 +4,16 @@
( function ( mw, $ ) {
$( function () {
mw.util.$content.dblclick( function ( e ) {
- e.preventDefault();
- // Trigger native HTMLElement click instead of opening URL (bug 43052)
- $( '#ca-edit a' ).get( 0 ).click();
+ // Recheck preference so extensions can do a hack to disable this code.
+ if ( parseInt( mw.user.options.get( 'editondblclick' ), 10 ) ) {
+ e.preventDefault();
+ // Trigger native HTMLElement click instead of opening URL (bug 43052)
+ var $a = $( '#ca-edit a' );
+ // Not every page has an edit link (bug 57713)
+ if ( $a.length ) {
+ $a.get( 0 ).click();
+ }
+ }
} );
} );
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.action/mediawiki.action.view.metadata.css b/resources/src/mediawiki.action/mediawiki.action.view.metadata.css
index 2c8d2e65..9f786ecb 100644
--- a/resources/src/mediawiki.action/mediawiki.action.view.metadata.css
+++ b/resources/src/mediawiki.action/mediawiki.action.view.metadata.css
@@ -4,3 +4,13 @@
table.collapsed tr.collapsable {
display: none;
}
+
+/*
+ * Exclude user interface elements from selection.
+ */
+.mw-metadata-show-hide-extended {
+ -moz-user-select: none;
+ -webkit-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
diff --git a/resources/src/mediawiki.action/mediawiki.action.view.postEdit.js b/resources/src/mediawiki.action/mediawiki.action.view.postEdit.js
index 4d2c47a5..c008dfd8 100644
--- a/resources/src/mediawiki.action/mediawiki.action.view.postEdit.js
+++ b/resources/src/mediawiki.action/mediawiki.action.view.postEdit.js
@@ -30,14 +30,7 @@
data.message = $.parseHTML( mw.message( 'postedit-confirmation-saved', data.user || mw.user ).escaped() );
}
- $div = $(
- '<div class="postedit-container">' +
- '<div class="postedit">' +
- '<div class="postedit-icon postedit-icon-checkmark postedit-content"></div>' +
- '<a href="#" class="postedit-close">&times;</a>' +
- '</div>' +
- '</div>'
- );
+ $div = mw.template.get( 'mediawiki.action.view.postEdit', 'postEdit.html' ).render();
if ( typeof data.message === 'string' ) {
$div.find( '.postedit-content' ).text( data.message );
@@ -83,4 +76,4 @@
mw.cookie.set( cookieKey, null );
}
-} ( mediaWiki, jQuery ) );
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.action/mediawiki.action.view.redirect.js b/resources/src/mediawiki.action/mediawiki.action.view.redirect.js
index 52e0d4e3..e66d8f69 100644
--- a/resources/src/mediawiki.action/mediawiki.action.view.redirect.js
+++ b/resources/src/mediawiki.action/mediawiki.action.view.redirect.js
@@ -11,9 +11,6 @@
fragment = null,
shouldChangeFragment, index;
- // Clear internal mw.config entries, so that no one tries to depend on them
- mw.config.set( 'wgInternalRedirectTargetUrl', null );
-
index = canonical.indexOf( '#' );
if ( index !== -1 ) {
fragment = canonical.slice( index );
diff --git a/resources/src/mediawiki.action/mediawiki.action.view.redirectPage.css b/resources/src/mediawiki.action/mediawiki.action.view.redirectPage.css
index fdbb655f..a92f1c16 100644
--- a/resources/src/mediawiki.action/mediawiki.action.view.redirectPage.css
+++ b/resources/src/mediawiki.action/mediawiki.action.view.redirectPage.css
@@ -24,15 +24,21 @@
margin: 0;
padding: 0;
padding-left: 42px;
+ background: transparent url(images/nextredirect-ltr.png) bottom left no-repeat;
/* @embed */
- background: url(images/nextredirect-ltr.png) bottom left no-repeat;
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/nextredirect-ltr.svg);
+ /* @embed */
+ background-image: linear-gradient(transparent, transparent), url(images/nextredirect-ltr.svg);
}
/* @noflip */
.mw-content-ltr .redirectText li:first-child {
padding-left: 47px;
+ background: transparent url(images/redirect-ltr.png) bottom left no-repeat;
+ /* @embed */
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/redirect-ltr.svg);
/* @embed */
- background: url(images/redirect-ltr.png) bottom left no-repeat;
+ background-image: linear-gradient(transparent, transparent), url(images/redirect-ltr.svg);
}
/* @noflip */
@@ -41,13 +47,19 @@
margin: 0;
padding: 0;
padding-right: 42px;
+ background: transparent url(images/nextredirect-rtl.png) bottom right no-repeat;
/* @embed */
- background: url(images/nextredirect-rtl.png) bottom right no-repeat;
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/nextredirect-rtl.svg);
+ /* @embed */
+ background-image: linear-gradient(transparent, transparent), url(images/nextredirect-rtl.svg);
}
/* @noflip */
.mw-content-rtl .redirectText li:first-child {
padding-right: 47px;
+ background: transparent url(images/redirect-rtl.png) bottom right no-repeat;
+ /* @embed */
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/redirect-rtl.svg);
/* @embed */
- background: url(images/redirect-rtl.png) bottom right no-repeat;
+ background-image: linear-gradient(transparent, transparent), url(images/redirect-rtl.svg);
}
diff --git a/resources/src/mediawiki.action/templates/postEdit.html b/resources/src/mediawiki.action/templates/postEdit.html
new file mode 100644
index 00000000..dbb482a6
--- /dev/null
+++ b/resources/src/mediawiki.action/templates/postEdit.html
@@ -0,0 +1,6 @@
+<div class="postedit-container">
+ <div class="postedit">
+ <div class="postedit-icon postedit-icon-checkmark postedit-content"></div>
+ <a href="#" class="postedit-close">&times;</a>
+ </div>
+</div>
diff --git a/resources/src/mediawiki.api/mediawiki.api.category.js b/resources/src/mediawiki.api/mediawiki.api.category.js
index 7dd9730f..14077e02 100644
--- a/resources/src/mediawiki.api/mediawiki.api.category.js
+++ b/resources/src/mediawiki.api/mediawiki.api.category.js
@@ -3,29 +3,21 @@
*/
( function ( mw, $ ) {
- var msg = 'Use of mediawiki.api callback params is deprecated. Use the Promise instead.';
$.extend( mw.Api.prototype, {
/**
* Determine if a category exists.
*
* @param {mw.Title|string} title
- * @param {Function} [ok] Success callback (deprecated)
- * @param {Function} [err] Error callback (deprecated)
* @return {jQuery.Promise}
* @return {Function} return.done
* @return {boolean} return.done.isCategory Whether the category exists.
*/
- isCategory: function ( title, ok, err ) {
+ isCategory: function ( title ) {
var apiPromise = this.get( {
prop: 'categoryinfo',
titles: String( title )
} );
- if ( ok || err ) {
- mw.track( 'mw.deprecate', 'api.cbParam' );
- mw.log.warn( msg );
- }
-
return apiPromise
.then( function ( data ) {
var exists = false;
@@ -38,8 +30,6 @@
}
return exists;
} )
- .done( ok )
- .fail( err )
.promise( { abort: apiPromise.abort } );
},
@@ -49,13 +39,11 @@
* E.g. given "Foo", return "Food", "Foolish people", "Foosball tables"...
*
* @param {string} prefix Prefix to match.
- * @param {Function} [ok] Success callback (deprecated)
- * @param {Function} [err] Error callback (deprecated)
* @return {jQuery.Promise}
* @return {Function} return.done
* @return {string[]} return.done.categories Matched categories
*/
- getCategoriesByPrefix: function ( prefix, ok, err ) {
+ getCategoriesByPrefix: function ( prefix ) {
// Fetch with allpages to only get categories that have a corresponding description page.
var apiPromise = this.get( {
list: 'allpages',
@@ -63,11 +51,6 @@
apnamespace: mw.config.get( 'wgNamespaceIds' ).category
} );
- if ( ok || err ) {
- mw.track( 'mw.deprecate', 'api.cbParam' );
- mw.log.warn( msg );
- }
-
return apiPromise
.then( function ( data ) {
var texts = [];
@@ -78,8 +61,6 @@
}
return texts;
} )
- .done( ok )
- .fail( err )
.promise( { abort: apiPromise.abort } );
},
@@ -87,34 +68,17 @@
* Get the categories that a particular page on the wiki belongs to.
*
* @param {mw.Title|string} title
- * @param {Function} [ok] Success callback (deprecated)
- * @param {Function} [err] Error callback (deprecated)
- * @param {boolean} [async=true] Asynchronousness (deprecated)
* @return {jQuery.Promise}
* @return {Function} return.done
* @return {boolean|mw.Title[]} return.done.categories List of category titles or false
* if title was not found.
*/
- getCategories: function ( title, ok, err, async ) {
+ getCategories: function ( title ) {
var apiPromise = this.get( {
prop: 'categories',
titles: String( title )
- }, {
- async: async === undefined ? true : async
} );
- if ( ok || err ) {
- mw.track( 'mw.deprecate', 'api.cbParam' );
- mw.log.warn( msg );
- }
- if ( async !== undefined ) {
- mw.track( 'mw.deprecate', 'api.async' );
- mw.log.warn(
- 'Use of mediawiki.api async=false param is deprecated. ' +
- 'The sychronous mode will be removed in the future.'
- );
- }
-
return apiPromise
.then( function ( data ) {
var titles = false;
@@ -132,8 +96,6 @@
}
return titles;
} )
- .done( ok )
- .fail( err )
.promise( { abort: apiPromise.abort } );
}
} );
diff --git a/resources/src/mediawiki.api/mediawiki.api.edit.js b/resources/src/mediawiki.api/mediawiki.api.edit.js
index e88ae5e2..dbe45bf6 100644
--- a/resources/src/mediawiki.api/mediawiki.api.edit.js
+++ b/resources/src/mediawiki.api/mediawiki.api.edit.js
@@ -3,7 +3,6 @@
*/
( function ( mw, $ ) {
- var msg = 'Use of mediawiki.api callback params is deprecated. Use the Promise instead.';
$.extend( mw.Api.prototype, {
/**
@@ -12,35 +11,21 @@
* cached token and start over.
*
* @param {Object} params API parameters
- * @param {Function} [ok] Success callback (deprecated)
- * @param {Function} [err] Error callback (deprecated)
* @return {jQuery.Promise} See #post
*/
- postWithEditToken: function ( params, ok, err ) {
- if ( ok || err ) {
- mw.track( 'mw.deprecate', 'api.cbParam' );
- mw.log.warn( msg );
- }
-
- return this.postWithToken( 'edit', params ).done( ok ).fail( err );
+ postWithEditToken: function ( params ) {
+ return this.postWithToken( 'edit', params );
},
/**
* API helper to grab an edit token.
*
- * @param {Function} [ok] Success callback (deprecated)
- * @param {Function} [err] Error callback (deprecated)
* @return {jQuery.Promise}
* @return {Function} return.done
* @return {string} return.done.token Received token.
*/
- getEditToken: function ( ok, err ) {
- if ( ok || err ) {
- mw.track( 'mw.deprecate', 'api.cbParam' );
- mw.log.warn( msg );
- }
-
- return this.getToken( 'edit' ).done( ok ).fail( err );
+ getEditToken: function () {
+ return this.getToken( 'edit' );
},
/**
@@ -50,32 +35,16 @@
* @param {string} header
* @param {string} message wikitext message
* @param {Object} [additionalParams] Additional API parameters, e.g. `{ redirect: true }`
- * @param {Function} [ok] Success handler (deprecated)
- * @param {Function} [err] Error handler (deprecated)
* @return {jQuery.Promise}
*/
- newSection: function ( title, header, message, additionalParams, ok, err ) {
- // Until we remove 'ok' and 'err' parameters, we have to support code that passes them,
- // but not additionalParams...
- if ( $.isFunction( additionalParams ) ) {
- err = ok;
- ok = additionalParams;
- additionalParams = undefined;
- }
-
- if ( ok || err ) {
- mw.track( 'mw.deprecate', 'api.cbParam' );
- mw.log.warn( msg );
- }
-
+ newSection: function ( title, header, message, additionalParams ) {
return this.postWithEditToken( $.extend( {
action: 'edit',
section: 'new',
- format: 'json',
title: String( title ),
summary: header,
text: message
- }, additionalParams ) ).done( ok ).fail( err );
+ }, additionalParams ) );
}
} );
diff --git a/resources/src/mediawiki.api/mediawiki.api.js b/resources/src/mediawiki.api/mediawiki.api.js
index 51b3238c..3a19e021 100644
--- a/resources/src/mediawiki.api/mediawiki.api.js
+++ b/resources/src/mediawiki.api/mediawiki.api.js
@@ -49,6 +49,16 @@
* console.log( data );
* } );
*
+ * Multiple values for a parameter can be specified using an array (since MW 1.25):
+ *
+ * var api = new mw.Api();
+ * api.get( {
+ * action: 'query',
+ * meta: [ 'userinfo', 'siteinfo' ] // same effect as 'userinfo|siteinfo'
+ * } ).done ( function ( data ) {
+ * console.log( data );
+ * } );
+ *
* @class
*
* @constructor
@@ -75,31 +85,14 @@
mw.Api.prototype = {
/**
- * Normalize the ajax options for compatibility and/or convenience methods.
- *
- * @param {Object} [arg] An object contaning one or more of options.ajax.
- * @return {Object} Normalized ajax options.
- */
- normalizeAjaxOptions: function ( arg ) {
- // Arg argument is usually empty
- // (before MW 1.20 it was used to pass ok callbacks)
- var opts = arg || {};
- // Options can also be a success callback handler
- if ( typeof arg === 'function' ) {
- opts = { ok: arg };
- }
- return opts;
- },
-
- /**
* Perform API get request
*
* @param {Object} parameters
- * @param {Object|Function} [ajaxOptions]
+ * @param {Object} [ajaxOptions]
* @return {jQuery.Promise}
*/
get: function ( parameters, ajaxOptions ) {
- ajaxOptions = this.normalizeAjaxOptions( ajaxOptions );
+ ajaxOptions = ajaxOptions || {};
ajaxOptions.type = 'GET';
return this.ajax( parameters, ajaxOptions );
},
@@ -110,11 +103,11 @@
* TODO: Post actions for non-local hostnames will need proxy.
*
* @param {Object} parameters
- * @param {Object|Function} [ajaxOptions]
+ * @param {Object} [ajaxOptions]
* @return {jQuery.Promise}
*/
post: function ( parameters, ajaxOptions ) {
- ajaxOptions = this.normalizeAjaxOptions( ajaxOptions );
+ ajaxOptions = ajaxOptions || {};
ajaxOptions.type = 'POST';
return this.ajax( parameters, ajaxOptions );
},
@@ -130,7 +123,6 @@
ajax: function ( parameters, ajaxOptions ) {
var token,
apiDeferred = $.Deferred(),
- msg = 'Use of mediawiki.api callback params is deprecated. Use the Promise instead.',
xhr, key, formData;
parameters = $.extend( {}, this.defaults.parameters, parameters );
@@ -142,6 +134,12 @@
delete parameters.token;
}
+ for ( key in parameters ) {
+ if ( $.isArray( parameters[key] ) ) {
+ parameters[key] = parameters[key].join( '|' );
+ }
+ }
+
// If multipart/form-data has been requested and emulation is possible, emulate it
if (
ajaxOptions.type === 'POST' &&
@@ -183,21 +181,6 @@
}
}
- // Backwards compatibility: Before MediaWiki 1.20,
- // callbacks were done with the 'ok' and 'err' property in ajaxOptions.
- if ( ajaxOptions.ok ) {
- mw.track( 'mw.deprecate', 'api.cbParam' );
- mw.log.warn( msg );
- apiDeferred.done( ajaxOptions.ok );
- delete ajaxOptions.ok;
- }
- if ( ajaxOptions.err ) {
- mw.track( 'mw.deprecate', 'api.cbParam' );
- mw.log.warn( msg );
- apiDeferred.fail( ajaxOptions.err );
- delete ajaxOptions.err;
- }
-
// Make the AJAX request
xhr = $.ajax( ajaxOptions )
// If AJAX fails, reject API call with error code 'http'
@@ -251,13 +234,7 @@
postWithToken: function ( tokenType, params, ajaxOptions ) {
var api = this;
- // Do not allow deprecated ok-callback
- // FIXME: Remove this check when the deprecated ok-callback is removed in #post
- if ( $.isFunction( ajaxOptions ) ) {
- ajaxOptions = undefined;
- }
-
- return api.getToken( tokenType ).then( function ( token ) {
+ return api.getToken( tokenType, params.assert ).then( function ( token ) {
params.token = token;
return api.post( params, ajaxOptions ).then(
// If no error, return to caller as-is
@@ -270,7 +247,7 @@
params.token = undefined;
// Try again, once
- return api.getToken( tokenType ).then( function ( token ) {
+ return api.getToken( tokenType, params.assert ).then( function ( token ) {
params.token = token;
return api.post( params, ajaxOptions );
} );
@@ -286,19 +263,21 @@
/**
* Get a token for a certain action from the API.
*
+ * The assert parameter is only for internal use by postWithToken.
+ *
* @param {string} type Token type
* @return {jQuery.Promise}
* @return {Function} return.done
* @return {string} return.done.token Received token.
* @since 1.22
*/
- getToken: function ( type ) {
+ getToken: function ( type, assert ) {
var apiPromise,
promiseGroup = promises[ this.defaults.ajax.url ],
d = promiseGroup && promiseGroup[ type + 'Token' ];
if ( !d ) {
- apiPromise = this.get( { action: 'tokens', type: type } );
+ apiPromise = this.get( { action: 'tokens', type: type, assert: assert } );
d = apiPromise
.then( function ( data ) {
@@ -357,7 +336,6 @@
'nomodule',
'mustbeposted',
'badaccess-groups',
- 'stashfailed',
'missingresult',
'missingparam',
'invalid-file-key',
@@ -379,7 +357,18 @@
'fetchfileerror',
'fileexists-shared-forbidden',
'invalidtitle',
- 'notloggedin'
+ 'notloggedin',
+
+ // Stash-specific errors - expanded
+ 'stashfailed',
+ 'stasherror',
+ 'stashedfilenotfound',
+ 'stashpathinvalid',
+ 'stashfilestorage',
+ 'stashzerolength',
+ 'stashnotloggedin',
+ 'stashwrongowner',
+ 'stashnosuchfilekey'
];
/**
diff --git a/resources/src/mediawiki.api/mediawiki.api.login.js b/resources/src/mediawiki.api/mediawiki.api.login.js
index ccbae06c..25257927 100644
--- a/resources/src/mediawiki.api/mediawiki.api.login.js
+++ b/resources/src/mediawiki.api/mediawiki.api.login.js
@@ -14,8 +14,7 @@
* @return {jQuery.Promise} See mw.Api#post
*/
login: function ( username, password ) {
- var params, request,
- deferred = $.Deferred(),
+ var params, apiPromise, innerPromise,
api = this;
params = {
@@ -24,25 +23,31 @@
lgpassword: password
};
- request = api.post( params );
- request.fail( deferred.reject );
- request.done( function ( data ) {
- params.lgtoken = data.login.token;
- api.post( params )
- .fail( deferred.reject )
- .done( function ( data ) {
- var code;
- if ( data.login && data.login.result === 'Success' ) {
- deferred.resolve( data );
- } else {
- // Set proper error code whenever possible
- code = data.error && data.error.code || 'unknown';
- deferred.reject( code, data );
- }
- } );
- } );
+ apiPromise = api.post( params );
- return deferred.promise( { abort: request.abort } );
+ return apiPromise
+ .then( function ( data ) {
+ params.lgtoken = data.login.token;
+ innerPromise = api.post( params )
+ .then( function ( data ) {
+ var code;
+ if ( data.login.result !== 'Success' ) {
+ // Set proper error code whenever possible
+ code = data.error && data.error.code || 'unknown';
+ return $.Deferred().reject( code, data );
+ }
+ return data;
+ } );
+ return innerPromise;
+ } )
+ .promise( {
+ abort: function () {
+ apiPromise.abort();
+ if ( innerPromise ) {
+ innerPromise.abort();
+ }
+ }
+ } );
}
} );
diff --git a/resources/src/mediawiki.api/mediawiki.api.options.js b/resources/src/mediawiki.api/mediawiki.api.options.js
new file mode 100644
index 00000000..b839fbdc
--- /dev/null
+++ b/resources/src/mediawiki.api/mediawiki.api.options.js
@@ -0,0 +1,89 @@
+/**
+ * @class mw.Api.plugin.options
+ */
+( function ( mw, $ ) {
+
+ $.extend( mw.Api.prototype, {
+
+ /**
+ * Asynchronously save the value of a single user option using the API. See #saveOptions.
+ *
+ * @param {string} name
+ * @param {string|null} value
+ * @return {jQuery.Promise}
+ */
+ saveOption: function ( name, value ) {
+ var param = {};
+ param[name] = value;
+ return this.saveOptions( param );
+ },
+
+ /**
+ * Asynchronously save the values of user options using the API.
+ *
+ * If a value of `null` is provided, the given option will be reset to the default value.
+ *
+ * Any warnings returned by the API, including warnings about invalid option names or values,
+ * are ignored. However, do not rely on this behavior.
+ *
+ * If necessary, the options will be saved using several parallel API requests. Only one promise
+ * is always returned that will be resolved when all requests complete.
+ *
+ * @param {Object} options Options as a `{ name: value, … }` object
+ * @return {jQuery.Promise}
+ */
+ saveOptions: function ( options ) {
+ var name, value, bundleable,
+ grouped = [],
+ deferreds = [];
+
+ for ( name in options ) {
+ value = options[name] === null ? null : String( options[name] );
+
+ // Can we bundle this option, or does it need a separate request?
+ bundleable =
+ ( value === null || value.indexOf( '|' ) === -1 ) &&
+ ( name.indexOf( '|' ) === -1 && name.indexOf( '=' ) === -1 );
+
+ if ( bundleable ) {
+ if ( value !== null ) {
+ grouped.push( name + '=' + value );
+ } else {
+ // Omitting value resets the option
+ grouped.push( name );
+ }
+ } else {
+ if ( value !== null ) {
+ deferreds.push( this.postWithToken( 'options', {
+ action: 'options',
+ optionname: name,
+ optionvalue: value
+ } ) );
+ } else {
+ // Omitting value resets the option
+ deferreds.push( this.postWithToken( 'options', {
+ action: 'options',
+ optionname: name
+ } ) );
+ }
+ }
+ }
+
+ if ( grouped.length ) {
+ deferreds.push( this.postWithToken( 'options', {
+ action: 'options',
+ change: grouped.join( '|' )
+ } ) );
+ }
+
+ return $.when.apply( $, deferreds );
+ }
+
+ } );
+
+ /**
+ * @class mw.Api
+ * @mixins mw.Api.plugin.options
+ */
+
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.api/mediawiki.api.parse.js b/resources/src/mediawiki.api/mediawiki.api.parse.js
index b1f1d2b0..2dcf8078 100644
--- a/resources/src/mediawiki.api/mediawiki.api.parse.js
+++ b/resources/src/mediawiki.api/mediawiki.api.parse.js
@@ -8,31 +8,21 @@
* Convenience method for 'action=parse'.
*
* @param {string} wikitext
- * @param {Function} [ok] Success callback (deprecated)
- * @param {Function} [err] Error callback (deprecated)
* @return {jQuery.Promise}
* @return {Function} return.done
* @return {string} return.done.data Parsed HTML of `wikitext`.
*/
- parse: function ( wikitext, ok, err ) {
+ parse: function ( wikitext ) {
var apiPromise = this.get( {
action: 'parse',
contentmodel: 'wikitext',
text: wikitext
} );
- // Backwards compatibility (< MW 1.20)
- if ( ok || err ) {
- mw.track( 'mw.deprecate', 'api.cbParam' );
- mw.log.warn( 'Use of mediawiki.api callback params is deprecated. Use the Promise instead.' );
- }
-
return apiPromise
.then( function ( data ) {
return data.parse.text['*'];
} )
- .done( ok )
- .fail( err )
.promise( { abort: apiPromise.abort } );
}
} );
diff --git a/resources/src/mediawiki.api/mediawiki.api.watch.js b/resources/src/mediawiki.api/mediawiki.api.watch.js
index af2dee10..40ba136d 100644
--- a/resources/src/mediawiki.api/mediawiki.api.watch.js
+++ b/resources/src/mediawiki.api/mediawiki.api.watch.js
@@ -12,8 +12,6 @@
* @param {string|mw.Title|string[]|mw.Title[]} pages Full page name or instance of mw.Title, or an
* array thereof. If an array is passed, the return value passed to the promise will also be an
* array of appropriate objects.
- * @param {Function} [ok] Success callback (deprecated)
- * @param {Function} [err] Error callback (deprecated)
* @return {jQuery.Promise}
* @return {Function} return.done
* @return {Object|Object[]} return.done.watch Object or list of objects (depends on the `pages`
@@ -22,7 +20,7 @@
* @return {boolean} return.done.watch.watched Whether the page is now watched or unwatched
* @return {string} return.done.watch.message Parsed HTML of the confirmational interface message
*/
- function doWatchInternal( pages, ok, err, addParams ) {
+ function doWatchInternal( pages, addParams ) {
// XXX: Parameter addParams is undocumented because we inherit this
// documentation in the public method...
var apiPromise = this.postWithToken( 'watch',
@@ -36,19 +34,11 @@
)
);
- // Backwards compatibility (< MW 1.20)
- if ( ok || err ) {
- mw.track( 'mw.deprecate', 'api.cbParam' );
- mw.log.warn( 'Use of mediawiki.api callback params is deprecated. Use the Promise instead.' );
- }
-
return apiPromise
.then( function ( data ) {
// If a single page was given (not an array) respond with a single item as well.
return $.isArray( pages ) ? data.watch : data.watch[0];
} )
- .done( ok )
- .fail( err )
.promise( { abort: apiPromise.abort } );
}
@@ -58,16 +48,17 @@
*
* @inheritdoc #doWatchInternal
*/
- watch: function ( pages, ok, err ) {
- return doWatchInternal.call( this, pages, ok, err );
+ watch: function ( pages ) {
+ return doWatchInternal.call( this, pages );
},
+
/**
* Convenience method for `action=watch&unwatch=1`.
*
* @inheritdoc #doWatchInternal
*/
- unwatch: function ( pages, ok, err ) {
- return doWatchInternal.call( this, pages, ok, err, { unwatch: 1 } );
+ unwatch: function ( pages ) {
+ return doWatchInternal.call( this, pages, { unwatch: 1 } );
}
} );
diff --git a/resources/src/mediawiki.language/languages/fi.js b/resources/src/mediawiki.language/languages/fi.js
index 453a675d..d9c2b06d 100644
--- a/resources/src/mediawiki.language/languages/fi.js
+++ b/resources/src/mediawiki.language/languages/fi.js
@@ -17,7 +17,7 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
if ( word.match( /wiki$/i ) ) {
aou = false;
}
- //append i after final consonant
+ // append i after final consonant
if ( word.match( /[bcdfghjklmnpqrstvwxz]$/i ) ) {
word += 'i';
}
diff --git a/resources/src/mediawiki.language/languages/hsb.js b/resources/src/mediawiki.language/languages/hsb.js
index 2d6b733e..2c0abd3d 100644
--- a/resources/src/mediawiki.language/languages/hsb.js
+++ b/resources/src/mediawiki.language/languages/hsb.js
@@ -14,6 +14,6 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
case 'lokatiw': // lokatiw
word = 'wo ' + word;
break;
- }
+ }
return word;
};
diff --git a/resources/src/mediawiki.language/languages/hy.js b/resources/src/mediawiki.language/languages/hy.js
index 9cae360b..c4a1cf73 100644
--- a/resources/src/mediawiki.language/languages/hy.js
+++ b/resources/src/mediawiki.language/languages/hy.js
@@ -24,6 +24,6 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
word = word + 'ի';
}
break;
- }
+ }
return word;
};
diff --git a/resources/src/mediawiki.language/languages/os.js b/resources/src/mediawiki.language/languages/os.js
index 787be36d..554e99d4 100644
--- a/resources/src/mediawiki.language/languages/os.js
+++ b/resources/src/mediawiki.language/languages/os.js
@@ -21,15 +21,14 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
if ( word.match( /тæ$/i ) ) {
word = word.slice( 0, -1 );
endAllative = 'æм';
- }
- // Works if word is in singular form.
- // Checking if word ends on one of the vowels: е, ё, и, о, ы, э, ю, я.
- else if ( word.match( /[аæеёиоыэюя]$/i ) ) {
+ } else if ( word.match( /[аæеёиоыэюя]$/i ) ) {
+ // Works if word is in singular form.
+ // Checking if word ends on one of the vowels: е, ё, и, о, ы, э, ю, я.
jot = 'й';
- }
- // Checking if word ends on 'у'. 'У' can be either consonant 'W' or vowel 'U' in cyrillic Ossetic.
- // Examples: {{grammar:genitive|аунеу}} = аунеуы, {{grammar:genitive|лæппу}} = лæппуйы.
- else if ( word.match( /у$/i ) ) {
+ } else if ( word.match( /у$/i ) ) {
+ // Checking if word ends on 'у'. 'У' can be either consonant 'W' or vowel 'U' in cyrillic Ossetic.
+ // Examples: {{grammar:genitive|аунеу}} = аунеуы, {{grammar:genitive|лæппу}} = лæппуйы.
+
if ( !word.slice( -2, -1 ).match( /[аæеёиоыэюя]$/i ) ) {
jot = 'й';
}
@@ -50,8 +49,7 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
case 'ablative':
if ( jot === 'й' ) {
ending = hyphen + jot + 'æ';
- }
- else {
+ } else {
ending = hyphen + jot + 'æй';
}
break;
diff --git a/resources/src/mediawiki.language/mediawiki.language.init.js b/resources/src/mediawiki.language/mediawiki.language.init.js
index df95d751..b3765c85 100644
--- a/resources/src/mediawiki.language/mediawiki.language.init.js
+++ b/resources/src/mediawiki.language/mediawiki.language.init.js
@@ -54,6 +54,7 @@
*/
getData: function ( langCode, dataKey ) {
var langData = mw.language.data;
+ langCode = langCode.toLowerCase();
if ( langData && langData[langCode] instanceof mw.Map ) {
return langData[langCode].get( dataKey );
}
@@ -71,6 +72,7 @@
*/
setData: function ( langCode, dataKey, value ) {
var langData = mw.language.data;
+ langCode = langCode.toLowerCase();
if ( !( langData[langCode] instanceof mw.Map ) ) {
langData[langCode] = new mw.Map();
}
diff --git a/resources/src/mediawiki.language/mediawiki.language.js b/resources/src/mediawiki.language/mediawiki.language.js
index d4f3c69e..78e39191 100644
--- a/resources/src/mediawiki.language/mediawiki.language.js
+++ b/resources/src/mediawiki.language/mediawiki.language.js
@@ -40,39 +40,18 @@ $.extend( mw.language, {
*
* @param {number} count Non-localized quantifier
* @param {Array} forms List of plural forms
+ * @param {Object} [explicitPluralForms] List of explicit plural forms
* @return {string} Correct form for quantifier in this language
*/
- convertPlural: function ( count, forms ) {
+ convertPlural: function ( count, forms, explicitPluralForms ) {
var pluralRules,
- formCount,
- form,
- index,
- equalsPosition,
pluralFormIndex = 0;
- if ( !forms || forms.length === 0 ) {
- return '';
- }
-
- // Handle for explicit n= forms
- for ( index = 0; index < forms.length; index++ ) {
- form = forms[index];
- if ( /^\d+=/.test( form ) ) {
- equalsPosition = form.indexOf( '=' );
- formCount = parseInt( form.slice( 0, equalsPosition ), 10 );
- if ( formCount === count ) {
- return form.slice( equalsPosition + 1 );
- }
- forms[index] = undefined;
- }
+ if ( explicitPluralForms && explicitPluralForms[count] ) {
+ return explicitPluralForms[count];
}
- // Remove explicit plural forms from the forms.
- forms = $.map( forms, function ( form ) {
- return form;
- } );
-
- if ( forms.length === 0 ) {
+ if ( !forms || forms.length === 0 ) {
return '';
}
@@ -107,7 +86,7 @@ $.extend( mw.language, {
* Usage in message text: `{{gender:[gender|user object]|masculine|feminine|neutral}}`.
* If second or third parameter are not specified, masculine is used.
*
- * These details may be overriden per language.
+ * These details may be overridden per language.
*
* @param {string} gender 'male', 'female', or anything else for neutral.
* @param {Array} forms List of gender forms
@@ -155,7 +134,9 @@ $.extend( mw.language, {
* @return {string}
*/
listToText: function ( list ) {
- var text = '', i = 0;
+ var text = '',
+ i = 0;
+
for ( ; i < list.length; i++ ) {
text += list[i];
if ( list.length - 2 === i ) {
@@ -165,6 +146,10 @@ $.extend( mw.language, {
}
}
return text;
+ },
+
+ setSpecialCharacters: function ( data ) {
+ this.specialCharacters = data;
}
} );
diff --git a/resources/src/mediawiki.language/mediawiki.language.numbers.js b/resources/src/mediawiki.language/mediawiki.language.numbers.js
index a0b81410..3c13055b 100644
--- a/resources/src/mediawiki.language/mediawiki.language.numbers.js
+++ b/resources/src/mediawiki.language/mediawiki.language.numbers.js
@@ -187,8 +187,12 @@
tmp[ transformTable[ i ] ] = i;
}
transformTable = tmp;
- numberString = num + '';
+ numberString = String( num );
} else {
+ // Ignore transform table if wgTranslateNumerals is false
+ if ( !mw.config.get( 'wgTranslateNumerals' ) ) {
+ transformTable = [];
+ }
numberString = mw.language.commafy( num, pattern );
}
diff --git a/resources/src/mediawiki.language/specialcharacters.json b/resources/src/mediawiki.language/specialcharacters.json
new file mode 100644
index 00000000..bab92a1b
--- /dev/null
+++ b/resources/src/mediawiki.language/specialcharacters.json
@@ -0,0 +1 @@
+{"latin":["Á","á","À","à","Â","â","Ä","ä","Ã","ã","Ǎ","ǎ","Ā","ā","Ă","ă","Ą","ą","Å","å","Ć","ć","Ĉ","ĉ","Ç","ç","Č","č","Ċ","ċ","Đ","đ","Ď","ď","É","é","È","è","Ê","ê","Ë","ë","Ě","ě","Ē","ē","Ĕ","ĕ","Ė","ė","Ę","ę","Ĝ","ĝ","Ģ","ģ","Ğ","ğ","Ġ","ġ","Ĥ","ĥ","Ħ","ħ","Í","í","Ì","ì","Î","î","Ï","ï","Ĩ","ĩ","Ǐ","ǐ","Ī","ī","Ĭ","ĭ","İ","ı","Į","į","Ĵ","ĵ","Ķ","ķ","Ĺ","ĺ","Ļ","ļ","Ľ","ľ","Ł","ł","Ń","ń","Ñ","ñ","Ņ","ņ","Ň","ň","Ó","ó","Ò","ò","Ô","ô","Ö","ö","Õ","õ","Ǒ","ǒ","Ō","ō","Ŏ","ŏ","Ǫ","ǫ","Ő","ő","Ŕ","ŕ","Ŗ","ŗ","Ř","ř","Ś","ś","Ŝ","ŝ","Ş","ş","Š","š","Ș","ș","Ț","ț","Ť","ť","Ú","ú","Ù","ù","Û","û","Ü","ü","Ũ","ũ","Ů","ů","Ǔ","ǔ","Ū","ū","ǖ","ǘ","ǚ","ǜ","Ŭ","ŭ","Ų","ų","Ű","ű","Ŵ","ŵ","Ý","ý","Ŷ","ŷ","Ÿ","ÿ","Ȳ","ȳ","Ź","ź","Ž","ž","Ż","ż","Æ","æ","Ǣ","ǣ","Ø","ø","Œ","œ","ß","Ð","ð","Þ","þ","Ə","ə"],"latinextended":["Ḁ","ḁ","ẚ","Ạ","ạ","Ả","ả","Ấ","ấ","Ầ","ầ","Ẩ","ẩ","Ẫ","ẫ","Ậ","ậ","Ắ","ắ","Ằ","ằ","Ẳ","ẳ","Ẵ","ẵ","Ặ","ặ","Ḃ","ḃ","Ḅ","ḅ","Ḇ","ḇ","Ḉ","ḉ","Ḋ","ḋ","Ḍ","ḍ","Ḏ","ḏ","Ḑ","ḑ","Ḓ","ḓ","Ḕ","ḕ","Ḗ","ḗ","Ḙ","ḙ","Ḛ","ḛ","Ḝ","ḝ","Ẹ","ẹ","Ẻ","ẻ","Ẽ","ẽ","Ế","ế","Ề","ề","Ể","ể","Ễ","ễ","Ệ","ệ","Ḟ","ḟ","Ḡ","ḡ","Ḣ","ḣ","Ḥ","ḥ","Ḧ","ḧ","Ḩ","ḩ","Ḫ","ḫ","ẖ","Ḭ","ḭ","Ḯ","ḯ","Ỉ","ỉ","Ị","ị","Ḱ","ḱ","Ḳ","ḳ","Ḵ","ḵ","Ḷ","ḷ","Ḹ","ḹ","Ḻ","ḻ","Ḽ","ḽ","Ỻ","ỻ","Ḿ","ḿ","Ṁ","ṁ","Ṃ","ṃ","Ṅ","ṅ","Ṇ","ṇ","Ṉ","ṉ","Ṋ","ṋ","Ṍ","ṍ","Ṏ","ṏ","Ṑ","ṑ","Ṓ","ṓ","Ọ","ọ","Ỏ","ỏ","Ố","ố","Ồ","ồ","Ổ","ổ","Ỗ","ỗ","Ộ","ộ","Ớ","ớ","Ờ","ờ","Ở","ở","Ỡ","ỡ","Ợ","ợ","Ǿ","ǿ","Ơ","ơ","Ṕ","ṕ","Ṗ","ṗ","Ṙ","ṙ","Ṛ","ṛ","Ṝ","ṝ","Ṟ","ṟ","Ṡ","ṡ","ẛ","Ṣ","ṣ","Ṥ","ṥ","Ṧ","ṧ","Ṩ","ṩ","ẜ","ẝ","Ṫ","ṫ","Ṭ","ṭ","Ṯ","ṯ","Ṱ","ṱ","ẗ","Ṳ","ṳ","Ṵ","ṵ","Ṷ","ṷ","Ṹ","ṹ","Ṻ","ṻ","Ụ","ụ","Ủ","ủ","Ứ","ứ","Ừ","ừ","Ử","ử","Ữ","ữ","Ự","ự","Ư","ư","Ǖ","Ǘ","Ǚ","Ǜ","Ṽ","ṽ","Ṿ","ṿ","Ỽ","ỽ","Ẁ","ẁ","Ẃ","ẃ","Ẅ","ẅ","Ẇ","ẇ","Ẉ","ẉ","ẘ","Ẋ","ẋ","Ẍ","ẍ","Ẏ","ẏ","ẙ","Ỳ","ỳ","Ỵ","ỵ","Ỷ","ỷ","Ỹ","ỹ","Ỿ","ỿ","Ẑ","ẑ","Ẓ","ẓ","Ẕ","ẕ","Ǽ","ǽ","ẞ","ẟ"],"ipa":["p","t̪","t","ʈ","c","k","q","ʡ","ʔ","b","d̪","d","ɖ","ɟ","ɡ","ɢ","ɓ","ɗ","ʄ","ɠ","ʛ","t͡s","t͡ʃ","t͡ɕ","d͡z","d͡ʒ","d͡ʑ","ɸ","f","θ","s","ʃ","ʅ","ʆ","ʂ","ɕ","ç","ɧ","x","χ","ħ","ʜ","h","β","v","ʍ","ð","z","ʒ","ʓ","ʐ","ʑ","ʝ","ɣ","ʁ","ʕ","ʖ","ʢ","ɦ","ɬ","ɮ","m","m̩","ɱ","ɱ̩","ɱ̍","n̪","n̪̍","n","n̩","ɳ","ɳ̩","ɲ","ɲ̩","ŋ","ŋ̍","ŋ̩","ɴ","ɴ̩","ʙ","ʙ̩","r","r̩","ʀ","ʀ̩","ɾ","ɽ","ɿ","ɺ","l̪","l̪̩","l","l̩","ɫ","ɫ̩","ɭ","ɭ̩","ʎ","ʎ̩","ʟ","ʟ̩","w","ɥ","ʋ","ɹ","ɻ","j","ɰ","ʘ","ǂ","ǀ","!","ǁ","ʰ","ʱ","ʷ","ʸ","ʲ","ʳ","ⁿ","ˡ","ʴ","ʵ","ˢ","ˣ","ˠ","ʶ","ˤ","ˁ","ˀ","ʼ","i","i̯","ĩ","y","y̯","ỹ","ɪ","ɪ̯","ɪ̃","ʏ","ʏ̯","ʏ̃","ɨ","ɨ̯","ɨ̃","ʉ","ʉ̯","ʉ̃","ɯ","ɯ̯","ɯ̃","u","u̯","ũ","ʊ","ʊ̯","ʊ̃","e","e̯","ẽ","ø","ø̯","ø̃","ɘ","ɘ̯","ɘ̃","ɵ","ɵ̯","ɵ̃","ɤ","ɤ̯","ɤ̃","o","o̯","õ","ɛ","ɛ̯","ɛ̃","œ","œ̯","œ̃","ɜ","ɜ̯","ɜ̃","ə","ə̯","ə̃","ɞ","ɞ̯","ɞ̃","ʌ","ʌ̯","ʌ̃","ɔ","ɔ̯","ɔ̃","æ","æ̯","æ̃","ɶ","ɶ̯","ɶ̃","a","a̯","ã","ɐ","ɐ̯","ɐ̃","ɑ","ɑ̯","ɑ̃","ɒ","ɒ̯","ɒ̃","ˈ","ˌ","ː","ˑ","˘",".","‿","|","‖","ɚ","ɝ"],"symbols":["~","|","¡","¿","†","‡","↔","↑","↓","•","¶","#","½","⅓","⅔","¼","¾","⅛","⅜","⅝","⅞","∞","‘","’",{"label":"“”","action":{"type":"encapsulate","options":{"pre":"“","post":"”"}}},{"label":"„“","action":{"type":"encapsulate","options":{"pre":"„","post":"“"}}},{"label":"„”","action":{"type":"encapsulate","options":{"pre":"„","post":"”"}}},{"label":"«»","action":{"type":"encapsulate","options":{"pre":"«","post":"»"}}},"¤","₳","฿","₵","¢","₡","₢","$","₫","₯","€","₠","₣","ƒ","₴","₭","₤","ℳ","₥","₦","№","₧","₰","£","៛","₨","₪","৳","₮","₩","¥","♠","♣","♥","♦","m²","m³",{"label":"–","titleMsg":"special-characters-title-endash","action":{"type":"replace","options":{"peri":"–","selectPeri":false}}},{"label":"—","titleMsg":"special-characters-title-emdash","action":{"type":"replace","options":{"peri":"—","selectPeri":false}}},"…","‘","’","“","”","°","′","″","≈","≠","≤","≥","±",{"label":"−","titleMsg":"special-characters-title-minus","action":{"type":"replace","options":{"peri":"−","selectPeri":false}}},"×","÷","←","→","·","§","‽"],"greek":["Α","Ά","α","ά","Β","β","Γ","γ","Δ","δ","Ε","Έ","ε","έ","Ζ","ζ","Η","Ή","η","ή","Θ","θ","Ι","Ί","ι","ί","Κ","κ","Λ","λ","Μ","μ","Ν","ν","Ξ","ξ","Ο","Ό","ο","ό","Π","π","Ρ","ρ","Σ","σ","ς","Τ","τ","Υ","Ύ","υ","ύ","Φ","φ","Χ","χ","Ψ","ψ","Ω","Ώ","ω","ώ"],"cyrillic":["А","а","Ӑ","ӑ","Ӓ","ӓ","Ә","ә","Ӛ","ӛ","Б","б","В","в","Г","г","Ґ","ґ","Ӷ","ӷ","Ѓ","ѓ","Ӻ","ӻ","Ғ","ғ","Ҕ","ҕ","Д","д","Ԁ","ԁ","Ԃ","ԃ","Ђ","ђ","Е","е","Ѐ","ѐ","Є","є","Ё","ё","Ӗ","ӗ","Ҽ","ҽ","Ҿ","ҿ","Ж","ж","Җ","җ","Ӂ","ӂ","Ӝ","ӝ","З","з","Ҙ","ҙ","Ӟ","ӟ","Ԑ","ԑ","Ӡ","ӡ","Ѕ","ѕ","Ԅ","ԅ","Ԇ","ԇ","И","и","І","і","Ї","ї",["◌Ӏ","Ӏ"],["◌ӏ","ӏ"],"Й","й","Ӣ","ӣ","Ѝ","ѝ","Ҋ","ҋ","Ӥ","ӥ","Ј","ј","К","к","Ќ","ќ","Қ","қ","Ҝ","ҝ","Ҟ","ҟ","Ҡ","ҡ","Ӄ","ӄ","Ԛ","ԛ","Л","л","Љ","љ","Ԉ","ԉ","Ԓ","ԓ","Ӆ","ӆ","М","м","Ӎ","ӎ","Н","н","Њ","њ","Ң","ң","Ҥ","ҥ","Ӈ","ӈ","Ԋ","ԋ","Ӊ","ӊ","О","о","Ҩ","ҩ","Ӧ","ӧ","Ө","ө","Ӫ","ӫ","П","п","Ԥ","ԥ","Ҧ","ҧ","Р","р","Ҏ","ҏ","С","с","Ҫ","ҫ","Т","т","Ћ","ћ","Ԍ","ԍ","Ҭ","ҭ","Ԏ","ԏ","У","у","Ў","ў","Ӯ","ӯ","Ӱ","ӱ","Ӳ","ӳ","Ү","ү","Ұ","ұ","Ф","ф","Х","х","Ҳ","ҳ","Ӽ","ӽ","Ӿ","ӿ","Һ","һ","Ц","ц","Ч","ч","Ҵ","ҵ","Ҷ","ҷ","Ҹ","ҹ","Ӌ","ӌ","Ӵ","ӵ","Џ","џ","Ш","ш","Щ","щ","Ъ","ъ","Ы","ы","Ӹ","ӹ","Ь","ь","Ҍ","ҍ","Э","э","Ӭ","ӭ","Ю","ю","Я","я","Ԝ","ԝ","Ѡ","ѡ","Ѣ","ѣ","Ѥ","ѥ","Ѧ","ѧ","Ѩ","ѩ","Ѫ","ѫ","Ѭ","ѭ","Ѯ","ѯ","Ѱ","ѱ","Ѳ","ѳ","Ѵ","ѵ","Ѷ","ѷ","Ѹ","ѹ","Ѻ","ѻ","Ѽ","ѽ","Ѿ","ѿ","Ҁ","ҁ"],"arabic":["ا","ب","ت","ث","ج","ح","خ","د","ذ","ر","ز","س","ش","ص","ض","ط","ظ","ع","غ","ف","ق","ك","ل","م","ن","ه","و","ي","ء","آ","أ","إ","ٱ","ؤ","ئ","ى","ة","َ","ُ","ِ","ً","ٌ","ٍ","ّ","ْ","ٰ","،","؛","؟","ـ","٠","١","٢","٣","٤","٥","٦","٧","٨","٩","٪","٫","٬","٭",["ZWNJ","‌"],["ZWJ","‍"]],"arabicextended":["ٲ","ٳ","ٴ","ٵ","ݳ","ݴ","ٮ","ٻ","پ","ڀ","ݐ","ݑ","ݒ","ݓ","ݔ","ݕ","ݖ","ٹ","ٺ","ټ","ٽ","ٿ","ځ","ڂ","ڃ","ڄ","څ","چ","ڇ","ڿ","ݗ","ݘ","ݮ","ݯ","ݲ","ݼ","ڈ","ډ","ڊ","ڋ","ڌ","ڍ","ڎ","ڏ","ڐ","ۮ","ݙ","ݚ","ڑ","ڒ","ړ","ڔ","ڕ","ږ","ڗ","ژ","ڙ","ۯ","ݛ","ݫ","ݬ","ݱ","ښ","ڛ","ڜ","ݽ","ۺ","ݜ","ݭ","ݰ","ݾ","ڝ","ڞ","ۻ","ڟ","ڠ","ݝ","ݞ","ݟ","ۼ","ڡ","ڢ","ڣ","ڤ","ڥ","ڦ","ݠ","ݡ","ٯ","ڧ","ڨ","ػ","ؼ","ک","ڪ","ګ","ڬ","ڭ","ڮ","گ","ڰ","ڱ","ڲ","ڳ","ڴ","ݢ","ݣ","ݤ","ݿ","ڵ","ڶ","ڷ","ڸ","ݪ","ݥ","ݦ","ڹ","ں","ڻ","ڼ","ڽ","ݧ","ݨ","ݩ","ھ","ۀ","ہ","ۂ","ۃ","ە","ۿ","ٶ","ٷ","ۄ","ۅ","ۆ","ۇ","ۈ","ۉ","ۊ","ۋ","ۏ","ݸ","ݹ","ؠ","ؽ","ؾ","ؿ","ٸ","ی","ۍ","ێ","ې","ۑ","ے","ۓ","ݵ","ݶ","ݷ","ݺ","ݻ","ٖ","ٗ","٘","ٙ","ٚ","ٛ","ٜ","ٝ","ٞ","ٟ","۔","۽","۾","۰","۱","۲","۳","۴","۵","۶","۷","۸","۹"],"hebrew":["א","ב","ג","ד","ה","ו","ז","ח","ט","י","כ","ך","ל","מ","ם","נ","ן","ס","ע","פ","ף","צ","ץ","ק","ר","ש","ת","װ","ױ","ײ","׳","״","־","–",{"label":"„”","action":{"type":"encapsulate","options":{"pre":"„","post":"”"}}},{"label":"‚’","action":{"type":"encapsulate","options":{"pre":"‚","post":"’"}}},["◌ְ","ְ"],["◌ֱ","ֱ"],["◌ֲ","ֲ"],["◌ֳ","ֳ"],["◌ִ","ִ"],["◌ֵ","ֵ"],["◌ֶ","ֶ"],["◌ַ","ַ"],["◌ָ","ָ"],["◌ֹ","ֹ"],["◌ֻ","ֻ"],["◌ּ","ּ"],["◌ׁ","ׁ"],["◌ׂ","ׂ"],["◌ׇ","ׇ"],["◌֑","֑"],["◌֒","֒"],["◌֓","֓"],["◌֔","֔"],["◌֕","֕"],["◌֖","֖"],["◌֗","֗"],["◌֘","֘"],["◌֙","֙"],["◌֚","֚"],["◌֛","֛"],["◌֜","֜"],["◌֝","֝"],["◌֞","֞"],["◌֟","֟"],["◌֠","֠"],["◌֡","֡"],["◌֢","֢"],["◌֣","֣"],["◌֤","֤"],["◌֥","֥"],["◌֦","֦"],["◌֧","֧"],["◌֨","֨"],["◌֩","֩"],["◌֪","֪"],["◌֫","֫"],["◌֬","֬"],["◌֭","֭"],["◌֮","֮"],["◌֯","֯"],["◌ֿ","ֿ"],["◌׀","׀"],["◌׃","׃"]],"bangla":["অ","আ","ই","ঈ","উ","ঊ","ঋ","এ","ঐ","ও","ঔ","া","ি","ী","ু","ূ","ৃ","ে","ৈ","ো","ৌ","ক","খ","গ","ঘ","ঙ","চ","ছ","জ","ঝ","ঞ","ট","ঠ","ড","ঢ","ণ","ত","থ","দ","ধ","ন","প","ফ","ব","ভ","ম","য","র","ল","শ","ষ","স","হ","ড়","ঢ়","য়","ৎ","ং","ঃ","ঁ","্","১","২","৩","৪","৫","৬","৭","৮","৯","০"],"tamil":["௦","௧","௨","௩","௪","௫","௬","௭","௮","௯","௰","௱","௲","௳","௴","௵","௶","௷","௸","௹","௺","ௐ"],"telugu":["ఁ","ం","ః","అ","ఆ","ఇ","ఈ","ఉ","ఊ","ఋ","ౠ","ఌ","ౡ","ఎ","ఏ","ఐ","ఒ","ఓ","ఔ","క","ఖ","గ","ఘ","ఙ","చ","ఛ","జ","ఝ","ఞ","ట","ఠ","డ","ఢ","ణ","త","థ","ద","ధ","న","ప","ఫ","బ","భ","మ","య","ర","ఱ","ల","ళ","వ","శ","ష","స","హ","ా","ి","ీ","ు","ూ","ృ","ౄ","ె","ే","ై","ొ","ో","ౌ","్","ౢ","ౣ","ౘ","ౙ","౦","౧","౨","౩","౪","౫","౬","౭","౮","౯","ఽ","౸","౹","౺","౻","౼","౽","౾","౿"],"sinhala":["අ","ආ","ඇ","ඈ","ඉ","ඊ","උ","ඌ","ඍ","ඎ","ඏ","ඐ","එ","ඒ","ඓ","ඔ","ඕ","ඖ","ක","ඛ","ග","ඝ","ඞ","ඟ","ච","ඡ","ජ","ඣ","ඤ","ඥ","ඦ","ට","ඨ","ඩ","ඪ","ණ","ඬ","ත","ථ","ද","ධ","න","ඳ","ප","ඵ","බ","භ","ම","ඹ","ය","ර","ල","ව","ශ","ෂ","ස","හ","ළ","ෆ",["◌ා","ා"],["◌ැ","ැ"],["◌ෑ","ෑ"],["◌ි","ි"],["◌ී","ී"],["◌ු","ු"],["◌ූ","ූ"],["◌ෘ","ෘ"],["◌ෲ","ෲ"],["◌ෟ","ෟ"],["◌ෳ","ෳ"],["◌ෙ","ෙ"],["◌ේ","ේ"],["◌ො","ො"],["◌ෝ","ෝ"],["◌ෞ","ෞ"],["◌්","්"]],"devanagari":["ऀ","ँ","ं","ः","ऄ","अ","आ","इ","ई","उ","ऊ","ऋ","ऌ","ऍ","ऎ","ए","ऐ","ऑ","ऒ","ओ","औ","क","ख","ग","घ","ङ","च","छ","ज","झ","ञ","ट","ठ","ड","ढ","ण","त","थ","द","ध","न","ऩ","प","फ","ब","भ","म","य","र","ऱ","ल","ळ","ऴ","व","श","ष","स","ह","ऺ","ऻ","़","ऽ","ा","ि","ी","ु","ू","ृ","ॄ","ॅ","ॆ","े","ै","ॉ","ॊ","ो","ौ","्","ॎ","ॏ","ॐ","॑","॒","॓","॔","ॕ","ॖ","ॗ","क़","ख़","ग़","ज़","ड़","ढ़","फ़","य़","ॠ","ॡ","ॢ","ॣ","।","॥","०","१","२","३","४","५","६","७","८","९","॰","ॱ","ॲ","ॳ","ॴ","ॵ","ॶ","ॷ","ॹ","ॺ","ॻ","ॼ","ॽ","ॾ","ॿ"],"gujarati":["ૐ","ઁ","ં","ઃ","અ","આ","ઇ","ઈ","ઉ","ઊ","એ","ઐ","ઓ","ઔ","અં","ઋ","ઍ","ઑ","ઌ","ૠ","ૡ","ક","ખ","ગ","ઘ","ઙ","ચ","છ","જ","ઝ","ઞ","ટ","ઠ","ડ","ઢ","ણ","ત","થ","દ","ધ","ન","પ","ફ","બ","ભ","મ","ય","ર","લ","ળ","વ","શ","ષ","સ","હ","ક્ષ","જ્ઞ","ઽ","ા","િ","ી","ી","ુ","ૂ","ૃ","ૄ","ૅ","ે","ૈ","ૉ","ો","ૌ","ૢ","ૣ","્","૦","૧","૨","૩","૪","૫","૬","૭","૮","૯","૱"],"thai":["ก","ข","ฃ","ค","ฅ","ฆ","ง","จ","ฉ","ช","ซ","ฌ","ญ","ฎ","ฏ","ฐ","ฑ","ฒ","ณ","ด","ต","ถ","ท","ธ","น","บ","ป","ผ","ฝ","พ","ฟ","ภ","ม","ย","ร","ฤ","ล","ฦ","ว","ศ","ษ","ส","ห","ฬ","อ","ฮ","ะ","ั","า","ๅ","ำ","ิ","ี","ึ","ื","ุ","ู","เ","แ","โ","ใ","ไ","็","่","้","๊","๋","์","ํ","ฺ","๎","๐","๑","๒","๓","๔","๕","๖","๗","๘","๙","฿","ๆ","ฯ","๚","๏","๛"],"lao":["ກ","ຂ","ຄ","ງ","ຈ","ສ","ຊ","ຍ","ດ","ຕ","ຖ","ທ","ນ","ບ","ປ","ຜ","ຝ","ພ","ຟ","ມ","ຢ","ລ","ວ","ຫ","ອ","ຮ","ຣ","ໜ","ໝ","ຼ","ຽ","ະ","ັ","າ","ຳ","ິ","ີ","ຶ","ື","ຸ","ູ","ົ","ເ","ແ","ໂ","ໃ","ໄ","່","້","໊","໋","໌","ໍ","໐","໑","໒","໓","໔","໕","໖","໗","໘","໙","₭","ໆ","ຯ"],"khmer":["ក","ខ","គ","ឃ","ង","ច","ឆ","ជ","ឈ","ញ","ដ","ឋ","ឌ","ឍ","ណ","ត","ថ","ទ","ធ","ន","ប","ផ","ព","ភ","ម","យ","រ","ល","វ","ស","ហ","ឡ","អ","ឣ","ឤ","ឥ","ឦ","ឧ","ឨ","ឩ","ឪ","ឫ","ឬ","ឭ","ឮ","ឯ","ឰ","ឱ","ឲ","ឳ","្","឴","឵","ា","ិ","ី","ឹ","ឺ","ុ","ូ","ួ","ើ","ឿ","ៀ","េ","ែ","ៃ","ោ","ៅ","ំ","ះ","ៈ","៉","៊","់","៌","៍","៎","៏","័","៑","៓","៝","ៜ","០","១","២","៣","៤","៥","៦","៧","៨","៩","៛","។","៕","៖","ៗ","៘","៙","៚","៰","៱","៲","៳","៴","៵","៶","៷","៸","៹","᧠","᧡","᧢","᧣","᧤","᧥","᧦","᧧","᧨","᧩","᧪","᧫","᧬","᧭","᧮","᧯","᧰","᧱","᧲","᧳","᧴","᧵","᧶","᧷","᧸","᧹","᧺","᧻","᧼","᧽","᧾","᧿"]} \ No newline at end of file
diff --git a/resources/src/mediawiki.legacy/ajax.js b/resources/src/mediawiki.legacy/ajax.js
index 6b9464a9..3660c205 100644
--- a/resources/src/mediawiki.legacy/ajax.js
+++ b/resources/src/mediawiki.legacy/ajax.js
@@ -5,190 +5,190 @@
* http://www.modernmethod.com/sajax/
*/
-/*jshint camelcase:false */
+/*jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
/*global alert */
( function ( mw ) {
-/**
- * if sajax_debug_mode is true, this function outputs given the message into
- * the element with id = sajax_debug; if no such element exists in the document,
- * it is injected.
- */
-function debug( text ) {
- if ( !window.sajax_debug_mode ) {
- return false;
- }
+ /**
+ * if sajax_debug_mode is true, this function outputs given the message into
+ * the element with id = sajax_debug; if no such element exists in the document,
+ * it is injected.
+ */
+ function debug( text ) {
+ if ( !window.sajax_debug_mode ) {
+ return false;
+ }
- var b, m,
- e = document.getElementById( 'sajax_debug' );
+ var b, m,
+ e = document.getElementById( 'sajax_debug' );
- if ( !e ) {
- e = document.createElement( 'p' );
- e.className = 'sajax_debug';
- e.id = 'sajax_debug';
+ if ( !e ) {
+ e = document.createElement( 'p' );
+ e.className = 'sajax_debug';
+ e.id = 'sajax_debug';
- b = document.getElementsByTagName( 'body' )[0];
+ b = document.getElementsByTagName( 'body' )[0];
- if ( b.firstChild ) {
- b.insertBefore( e, b.firstChild );
- } else {
- b.appendChild( e );
+ if ( b.firstChild ) {
+ b.insertBefore( e, b.firstChild );
+ } else {
+ b.appendChild( e );
+ }
}
- }
- m = document.createElement( 'div' );
- m.appendChild( document.createTextNode( text ) );
+ m = document.createElement( 'div' );
+ m.appendChild( document.createTextNode( text ) );
- e.appendChild( m );
+ e.appendChild( m );
- return true;
-}
+ return true;
+ }
-/**
- * Compatibility wrapper for creating a new XMLHttpRequest object.
- */
-function createXhr() {
- debug( 'sajax_init_object() called..' );
- var a;
- try {
- // Try the new style before ActiveX so we don't
- // unnecessarily trigger warnings in IE 7 when
- // set to prompt about ActiveX usage
- a = new XMLHttpRequest();
- } catch ( xhrE ) {
+ /**
+ * Compatibility wrapper for creating a new XMLHttpRequest object.
+ */
+ function createXhr() {
+ debug( 'sajax_init_object() called..' );
+ var a;
try {
- a = new window.ActiveXObject( 'Msxml2.XMLHTTP' );
- } catch ( msXmlE ) {
+ // Try the new style before ActiveX so we don't
+ // unnecessarily trigger warnings in IE 7 when
+ // set to prompt about ActiveX usage
+ a = new XMLHttpRequest();
+ } catch ( xhrE ) {
try {
- a = new window.ActiveXObject( 'Microsoft.XMLHTTP' );
- } catch ( msXhrE ) {
- a = null;
+ a = new window.ActiveXObject( 'Msxml2.XMLHTTP' );
+ } catch ( msXmlE ) {
+ try {
+ a = new window.ActiveXObject( 'Microsoft.XMLHTTP' );
+ } catch ( msXhrE ) {
+ a = null;
+ }
}
}
- }
- if ( !a ) {
- debug( 'Could not create connection object.' );
- }
+ if ( !a ) {
+ debug( 'Could not create connection object.' );
+ }
- return a;
-}
+ return a;
+ }
-/**
- * Perform an AJAX call to MediaWiki. Calls are handled by AjaxDispatcher.php
- * func_name - the name of the function to call. Must be registered in $wgAjaxExportList
- * args - an array of arguments to that function
- * target - the target that will handle the result of the call. If this is a function,
- * if will be called with the XMLHttpRequest as a parameter; if it's an input
- * element, its value will be set to the resultText; if it's another type of
- * element, its innerHTML will be set to the resultText.
- *
- * Example:
- * sajax_do_call( 'doFoo', [1, 2, 3], document.getElementById( 'showFoo' ) );
- *
- * This will call the doFoo function via MediaWiki's AjaxDispatcher, with
- * (1, 2, 3) as the parameter list, and will show the result in the element
- * with id = showFoo
- */
-function doAjaxRequest( func_name, args, target ) {
- var i, x, uri, post_data;
- uri = mw.util.wikiScript() + '?action=ajax';
- if ( window.sajax_request_type === 'GET' ) {
- if ( uri.indexOf( '?' ) === -1 ) {
- uri = uri + '?rs=' + encodeURIComponent( func_name );
+ /**
+ * Perform an AJAX call to MediaWiki. Calls are handled by AjaxDispatcher.php
+ * func_name - the name of the function to call. Must be registered in $wgAjaxExportList
+ * args - an array of arguments to that function
+ * target - the target that will handle the result of the call. If this is a function,
+ * if will be called with the XMLHttpRequest as a parameter; if it's an input
+ * element, its value will be set to the resultText; if it's another type of
+ * element, its innerHTML will be set to the resultText.
+ *
+ * Example:
+ * sajax_do_call( 'doFoo', [1, 2, 3], document.getElementById( 'showFoo' ) );
+ *
+ * This will call the doFoo function via MediaWiki's AjaxDispatcher, with
+ * (1, 2, 3) as the parameter list, and will show the result in the element
+ * with id = showFoo
+ */
+ function doAjaxRequest( func_name, args, target ) {
+ var i, x, uri, post_data;
+ uri = mw.util.wikiScript() + '?action=ajax';
+ if ( window.sajax_request_type === 'GET' ) {
+ if ( uri.indexOf( '?' ) === -1 ) {
+ uri = uri + '?rs=' + encodeURIComponent( func_name );
+ } else {
+ uri = uri + '&rs=' + encodeURIComponent( func_name );
+ }
+ for ( i = 0; i < args.length; i++ ) {
+ uri = uri + '&rsargs[]=' + encodeURIComponent( args[i] );
+ }
+ // uri = uri + '&rsrnd=' + new Date().getTime();
+ post_data = null;
} else {
- uri = uri + '&rs=' + encodeURIComponent( func_name );
- }
- for ( i = 0; i < args.length; i++ ) {
- uri = uri + '&rsargs[]=' + encodeURIComponent( args[i] );
+ post_data = 'rs=' + encodeURIComponent( func_name );
+ for ( i = 0; i < args.length; i++ ) {
+ post_data = post_data + '&rsargs[]=' + encodeURIComponent( args[i] );
+ }
}
- //uri = uri + '&rsrnd=' + new Date().getTime();
- post_data = null;
- } else {
- post_data = 'rs=' + encodeURIComponent( func_name );
- for ( i = 0; i < args.length; i++ ) {
- post_data = post_data + '&rsargs[]=' + encodeURIComponent( args[i] );
+ x = createXhr();
+ if ( !x ) {
+ alert( 'AJAX not supported' );
+ return false;
}
- }
- x = createXhr();
- if ( !x ) {
- alert( 'AJAX not supported' );
- return false;
- }
- try {
- x.open( window.sajax_request_type, uri, true );
- } catch ( e ) {
- if ( location.hostname === 'localhost' ) {
- alert( 'Your browser blocks XMLHttpRequest to "localhost", try using a real hostname for development/testing.' );
+ try {
+ x.open( window.sajax_request_type, uri, true );
+ } catch ( e ) {
+ if ( location.hostname === 'localhost' ) {
+ alert( 'Your browser blocks XMLHttpRequest to "localhost", try using a real hostname for development/testing.' );
+ }
+ throw e;
}
- throw e;
- }
- if ( window.sajax_request_type === 'POST' ) {
- x.setRequestHeader( 'Method', 'POST ' + uri + ' HTTP/1.1' );
- x.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
- }
- x.setRequestHeader( 'Pragma', 'cache=yes' );
- x.setRequestHeader( 'Cache-Control', 'no-transform' );
- x.onreadystatechange = function () {
- if ( x.readyState !== 4 ) {
- return;
+ if ( window.sajax_request_type === 'POST' ) {
+ x.setRequestHeader( 'Method', 'POST ' + uri + ' HTTP/1.1' );
+ x.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
}
+ x.setRequestHeader( 'Pragma', 'cache=yes' );
+ x.setRequestHeader( 'Cache-Control', 'no-transform' );
+ x.onreadystatechange = function () {
+ if ( x.readyState !== 4 ) {
+ return;
+ }
- debug( 'received (' + x.status + ' ' + x.statusText + ') ' + x.responseText );
+ debug( 'received (' + x.status + ' ' + x.statusText + ') ' + x.responseText );
- //if ( x.status != 200 )
- // alert( 'Error: ' + x.status + ' ' + x.statusText + ': ' + x.responseText );
- //else
+ // if ( x.status != 200 )
+ // alert( 'Error: ' + x.status + ' ' + x.statusText + ': ' + x.responseText );
+ // else
- if ( typeof target === 'function' ) {
- target( x );
- } else if ( typeof target === 'object' ) {
- if ( target.tagName === 'INPUT' ) {
- if ( x.status === 200 ) {
- target.value = x.responseText;
- }
- //else alert( 'Error: ' + x.status + ' ' + x.statusText + ' (' + x.responseText + ')' );
- } else {
- if ( x.status === 200 ) {
- target.innerHTML = x.responseText;
+ if ( typeof target === 'function' ) {
+ target( x );
+ } else if ( typeof target === 'object' ) {
+ if ( target.tagName === 'INPUT' ) {
+ if ( x.status === 200 ) {
+ target.value = x.responseText;
+ }
+ // else alert( 'Error: ' + x.status + ' ' + x.statusText + ' (' + x.responseText + ')' );
} else {
- target.innerHTML = '<div class="error">Error: ' + x.status +
- ' ' + x.statusText + ' (' + x.responseText + ')</div>';
+ if ( x.status === 200 ) {
+ target.innerHTML = x.responseText;
+ } else {
+ target.innerHTML = '<div class="error">Error: ' + x.status +
+ ' ' + x.statusText + ' (' + x.responseText + ')</div>';
+ }
}
+ } else {
+ alert( 'Bad target for sajax_do_call: not a function or object: ' + target );
}
- } else {
- alert( 'Bad target for sajax_do_call: not a function or object: ' + target );
- }
- };
+ };
+
+ debug( func_name + ' uri = ' + uri + ' / post = ' + post_data );
+ x.send( post_data );
+ debug( func_name + ' waiting..' );
- debug( func_name + ' uri = ' + uri + ' / post = ' + post_data );
- x.send( post_data );
- debug( func_name + ' waiting..' );
+ return true;
+ }
- return true;
-}
+ /**
+ * @return {boolean} Whether the browser supports AJAX
+ */
+ function wfSupportsAjax() {
+ var request = createXhr(),
+ supportsAjax = request ? true : false;
-/**
- * @return {boolean} Whether the browser supports AJAX
- */
-function wfSupportsAjax() {
- var request = createXhr(),
- supportsAjax = request ? true : false;
-
- request = undefined;
- return supportsAjax;
-}
-
-// Expose + Mark as deprecated
-var deprecationNotice = 'Sajax is deprecated, use jQuery.ajax or mediawiki.api instead.';
-
-// Variables
-mw.log.deprecate( window, 'sajax_debug_mode', false, deprecationNotice );
-mw.log.deprecate( window, 'sajax_request_type', 'GET', deprecationNotice );
-// Methods
-mw.log.deprecate( window, 'sajax_debug', debug, deprecationNotice );
-mw.log.deprecate( window, 'sajax_init_object', createXhr, deprecationNotice );
-mw.log.deprecate( window, 'sajax_do_call', doAjaxRequest, deprecationNotice );
-mw.log.deprecate( window, 'wfSupportsAjax', wfSupportsAjax, deprecationNotice );
+ request = undefined;
+ return supportsAjax;
+ }
+
+ // Expose + Mark as deprecated
+ var deprecationNotice = 'Sajax is deprecated, use jQuery.ajax or mediawiki.api instead.';
+
+ // Variables
+ mw.log.deprecate( window, 'sajax_debug_mode', false, deprecationNotice );
+ mw.log.deprecate( window, 'sajax_request_type', 'GET', deprecationNotice );
+ // Methods
+ mw.log.deprecate( window, 'sajax_debug', debug, deprecationNotice );
+ mw.log.deprecate( window, 'sajax_init_object', createXhr, deprecationNotice );
+ mw.log.deprecate( window, 'sajax_do_call', doAjaxRequest, deprecationNotice );
+ mw.log.deprecate( window, 'wfSupportsAjax', wfSupportsAjax, deprecationNotice );
}( mediaWiki ) );
diff --git a/resources/src/mediawiki.legacy/commonPrint.css b/resources/src/mediawiki.legacy/commonPrint.css
index 830b02fa..9a8d3918 100644
--- a/resources/src/mediawiki.legacy/commonPrint.css
+++ b/resources/src/mediawiki.legacy/commonPrint.css
@@ -23,7 +23,6 @@ div#column-one,
#toc.tochidden,
div#f-poweredbyico,
div#f-copyrightico,
-li#viewcount,
li#about,
li#disclaimer,
li#mobileview,
@@ -35,6 +34,7 @@ span.mw-filepage-other-resolutions,
#filetoc,
.usermessage,
.patrollink,
+.ns-0 .mw-redirectedfrom,
#mw-navigation,
#siteNotice {
display: none;
@@ -203,6 +203,7 @@ a.stub {
/**
* Floating divs
*/
+/* @noflip */
div.floatright {
float: right;
clear: right;
@@ -214,6 +215,7 @@ div.floatright p {
font-style: italic;
}
+/* @noflip */
div.floatleft {
float: left;
clear: left;
@@ -323,44 +325,6 @@ div.gallerytext {
}
/**
- * Diff rendering
- */
-table.diff {
- background: white;
-}
-
-td.diff-otitle {
- background: #ffffff;
-}
-
-td.diff-ntitle {
- background: #ffffff;
-}
-
-td.diff-addedline {
- background: #ccffcc;
- font-size: smaller;
- border: solid 2px black;
-}
-
-td.diff-deletedline {
- background: #ffffaa;
- font-size: smaller;
- border: dotted 2px black;
-}
-
-td.diff-context {
- background: #eeeeee;
- font-size: smaller;
-}
-
-.diffchange {
- color: silver;
- font-weight: bold;
- text-decoration: underline;
-}
-
-/**
* Table rendering
* As on shared.css but with white background.
*/
diff --git a/resources/src/mediawiki.legacy/images/magnify-clip-ltr.png b/resources/src/mediawiki.legacy/images/magnify-clip-ltr.png
new file mode 100644
index 00000000..712b1b48
--- /dev/null
+++ b/resources/src/mediawiki.legacy/images/magnify-clip-ltr.png
Binary files differ
diff --git a/resources/src/mediawiki.legacy/images/magnify-clip-ltr.svg b/resources/src/mediawiki.legacy/images/magnify-clip-ltr.svg
new file mode 100644
index 00000000..4d3dcb65
--- /dev/null
+++ b/resources/src/mediawiki.legacy/images/magnify-clip-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 15" width="15" height="11">
+ <g id="magnify-clip" fill="#fff" stroke="#000">
+ <path id="bigbox" d="M1.509 1.865h10.99v7.919h-10.99z"/>
+ <path id="smallbox" d="M-1.499 6.868h5.943v4.904h-5.943z"/>
+ </g>
+</svg>
diff --git a/resources/src/mediawiki.legacy/images/magnify-clip-rtl.png b/resources/src/mediawiki.legacy/images/magnify-clip-rtl.png
new file mode 100644
index 00000000..1d03a8c0
--- /dev/null
+++ b/resources/src/mediawiki.legacy/images/magnify-clip-rtl.png
Binary files differ
diff --git a/resources/src/mediawiki.legacy/images/magnify-clip-rtl.svg b/resources/src/mediawiki.legacy/images/magnify-clip-rtl.svg
new file mode 100644
index 00000000..582e4ae7
--- /dev/null
+++ b/resources/src/mediawiki.legacy/images/magnify-clip-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 15" width="15" height="11">
+ <g id="magnify-clip" fill="#fff" stroke="#000">
+ <path id="bigbox" d="M9.491 1.865h-10.99v7.919h10.99z"/>
+ <path id="smallbox" d="M12.499 6.868h-5.943v4.904h5.943z"/>
+ </g>
+</svg>
diff --git a/resources/src/mediawiki.legacy/oldshared.css b/resources/src/mediawiki.legacy/oldshared.css
index d92d3bb9..c2bd5a73 100644
--- a/resources/src/mediawiki.legacy/oldshared.css
+++ b/resources/src/mediawiki.legacy/oldshared.css
@@ -119,8 +119,12 @@ div.magnify a {
/* …and replace it with the image */
width: 15px;
height: 11px;
- /* @embed */
+ /* Use same SVG support hack as mediawiki.legacy's shared.css */
background: url(images/magnify-clip-ltr.png) center center no-repeat;
+ /* @embed */
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
+ /* @embed */
+ background-image: linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
/* Don't annoy people who copy-paste everything too much */
-moz-user-select: none;
-webkit-user-select: none;
diff --git a/resources/src/mediawiki.legacy/protect.js b/resources/src/mediawiki.legacy/protect.js
index f9069b6f..3f4b263e 100644
--- a/resources/src/mediawiki.legacy/protect.js
+++ b/resources/src/mediawiki.legacy/protect.js
@@ -6,7 +6,8 @@ var ProtectionForm = window.ProtectionForm = {
* on the protection form
*/
init: function () {
- var $cell = $( '<td>' ), $row = $( '<tr>' ).append( $cell );
+ var $cell = $( '<td>' ),
+ $row = $( '<tr>' ).append( $cell );
if ( !$( '#mwProtectSet' ).length ) {
return false;
@@ -63,7 +64,7 @@ var ProtectionForm = window.ProtectionForm = {
},
/**
- * Checks if a cerain protection level is cascadeable.
+ * Checks if a certain protection level is cascadeable.
*
* @param {string} level
* @return {boolean}
diff --git a/resources/src/mediawiki.legacy/shared.css b/resources/src/mediawiki.legacy/shared.css
index 0604773e..3657b127 100644
--- a/resources/src/mediawiki.legacy/shared.css
+++ b/resources/src/mediawiki.legacy/shared.css
@@ -91,6 +91,18 @@ abbr[title],
color: #aaa; /* gray */
}
+/*
+ * Bidi-isolate these numbers.
+ * See https://phabricator.wikimedia.org/T93484
+ */
+.mw-plusminus-pos,
+.mw-plusminus-neg,
+.mw-plusminus-null {
+ unicode-bidi: -moz-isolate;
+ unicode-bidi: -webkit-isolate;
+ unicode-bidi: isolate;
+}
+
/**
* Links to redirects appear italicized on [[Special:AllPages]], [[Special:PrefixIndex]],
* [[Special:Watchlist/edit]] and in category listings.
@@ -414,7 +426,7 @@ p.mw-upload-editlicenses {
border: 1px dashed #aaa;
}
-.mw-history-revisiondelete-button, #mw-fileduplicatesearch-icon {
+.mw-history-revisionactions, #mw-fileduplicatesearch-icon {
float: right;
}
@@ -506,7 +518,7 @@ a.feedlink {
table.wikitable {
margin: 1em 0;
background-color: #f9f9f9;
- border: 1px #aaa solid;
+ border: 1px solid #aaa;
border-collapse: collapse;
color: black;
}
@@ -515,8 +527,8 @@ table.wikitable > tr > th,
table.wikitable > tr > td,
table.wikitable > * > tr > th,
table.wikitable > * > tr > td {
- border: 1px #aaa solid;
- padding: 0.2em;
+ border: 1px solid #aaa;
+ padding: 0.2em 0.4em;
}
table.wikitable > tr > th,
@@ -584,7 +596,7 @@ table.wikitable > caption {
}
.successbox {
- color: #009000;
+ color: #008000;
border-color: #b7fdb5;
background-color: #e1fddf;
}
@@ -934,11 +946,14 @@ h2:lang(te), h3:lang(te), h4:lang(te), h5:lang(te), h6:lang(te) {
/* Localised ordered list numbering for some languages */
ol:lang(bcc) li,
+ol:lang(bgn) li,
ol:lang(bqi) li,
ol:lang(fa) li,
ol:lang(glk) li,
ol:lang(kk-arab) li,
-ol:lang(mzn) li {
+ol:lang(lrc) li,
+ol:lang(mzn) li,
+ol:lang(sdh) li {
list-style-type: -moz-persian;
list-style-type: persian;
}
@@ -1124,6 +1139,7 @@ table.floatleft {
.mw-editsection,
.toctoggle,
+.tochidden,
#jump-to-nav {
-moz-user-select: none;
-webkit-user-select: none;
diff --git a/resources/src/mediawiki.legacy/wikibits.js b/resources/src/mediawiki.legacy/wikibits.js
index a4039966..32cd79a5 100644
--- a/resources/src/mediawiki.legacy/wikibits.js
+++ b/resources/src/mediawiki.legacy/wikibits.js
@@ -5,200 +5,214 @@
var msg,
win = window,
ua = navigator.userAgent.toLowerCase(),
- onloadFuncts = [];
-
-/**
- * User-agent sniffing.
- *
- * @deprecated since 1.17 Use jquery.client instead
- */
-
-msg = 'Use feature detection or module jquery.client instead.';
-
-mw.log.deprecate( win, 'clientPC', ua, msg );
-
-// Ignored dummy values
-mw.log.deprecate( win, 'is_gecko', false, msg );
-mw.log.deprecate( win, 'is_chrome_mac', false, msg );
-mw.log.deprecate( win, 'is_chrome', false, msg );
-mw.log.deprecate( win, 'webkit_version', false, msg );
-mw.log.deprecate( win, 'is_safari_win', false, msg );
-mw.log.deprecate( win, 'is_safari', false, msg );
-mw.log.deprecate( win, 'webkit_match', false, msg );
-mw.log.deprecate( win, 'is_ff2', false, msg );
-mw.log.deprecate( win, 'ff2_bugs', false, msg );
-mw.log.deprecate( win, 'is_ff2_win', false, msg );
-mw.log.deprecate( win, 'is_ff2_x11', false, msg );
-mw.log.deprecate( win, 'opera95_bugs', false, msg );
-mw.log.deprecate( win, 'opera7_bugs', false, msg );
-mw.log.deprecate( win, 'opera6_bugs', false, msg );
-mw.log.deprecate( win, 'is_opera_95', false, msg );
-mw.log.deprecate( win, 'is_opera_preseven', false, msg );
-mw.log.deprecate( win, 'is_opera', false, msg );
-mw.log.deprecate( win, 'ie6_bugs', false, msg );
-
-/**
- * DOM utilities for handling of events, text nodes and selecting elements
- *
- * @deprecated since 1.17 Use jQuery instead
- */
-msg = 'Use jQuery instead.';
-
-// Ignored dummy values
-mw.log.deprecate( win, 'doneOnloadHook', undefined, msg );
-mw.log.deprecate( win, 'onloadFuncts', [], msg );
-mw.log.deprecate( win, 'runOnloadHook', $.noop, msg );
-mw.log.deprecate( win, 'changeText', $.noop, msg );
-mw.log.deprecate( win, 'killEvt', $.noop, msg );
-mw.log.deprecate( win, 'addHandler', $.noop, msg );
-mw.log.deprecate( win, 'hookEvent', $.noop, msg );
-mw.log.deprecate( win, 'addClickHandler', $.noop, msg );
-mw.log.deprecate( win, 'removeHandler', $.noop, msg );
-mw.log.deprecate( win, 'getElementsByClassName', function () { return []; }, msg );
-mw.log.deprecate( win, 'getInnerText', function () { return ''; }, msg );
-
-// Run a function after the window onload event is fired
-mw.log.deprecate( win, 'addOnloadHook', function ( hookFunct ) {
- if ( onloadFuncts ) {
- onloadFuncts.push(hookFunct);
- } else {
- // If func queue is gone the event has happened already,
- // run immediately instead of queueing.
- hookFunct();
+ onloadFuncts = [],
+ loadedScripts = {};
+
+ /**
+ * User-agent sniffing.
+ *
+ * @deprecated since 1.17 Use jquery.client instead
+ */
+
+ msg = 'Use feature detection or module jquery.client instead.';
+
+ mw.log.deprecate( win, 'clientPC', ua, msg );
+
+ // Ignored dummy values
+ mw.log.deprecate( win, 'is_gecko', false, msg );
+ mw.log.deprecate( win, 'is_chrome_mac', false, msg );
+ mw.log.deprecate( win, 'is_chrome', false, msg );
+ mw.log.deprecate( win, 'webkit_version', false, msg );
+ mw.log.deprecate( win, 'is_safari_win', false, msg );
+ mw.log.deprecate( win, 'is_safari', false, msg );
+ mw.log.deprecate( win, 'webkit_match', false, msg );
+ mw.log.deprecate( win, 'is_ff2', false, msg );
+ mw.log.deprecate( win, 'ff2_bugs', false, msg );
+ mw.log.deprecate( win, 'is_ff2_win', false, msg );
+ mw.log.deprecate( win, 'is_ff2_x11', false, msg );
+ mw.log.deprecate( win, 'opera95_bugs', false, msg );
+ mw.log.deprecate( win, 'opera7_bugs', false, msg );
+ mw.log.deprecate( win, 'opera6_bugs', false, msg );
+ mw.log.deprecate( win, 'is_opera_95', false, msg );
+ mw.log.deprecate( win, 'is_opera_preseven', false, msg );
+ mw.log.deprecate( win, 'is_opera', false, msg );
+ mw.log.deprecate( win, 'ie6_bugs', false, msg );
+
+ /**
+ * DOM utilities for handling of events, text nodes and selecting elements
+ *
+ * @deprecated since 1.17 Use jQuery instead
+ */
+ msg = 'Use jQuery instead.';
+
+ // Ignored dummy values
+ mw.log.deprecate( win, 'doneOnloadHook', undefined, msg );
+ mw.log.deprecate( win, 'onloadFuncts', [], msg );
+ mw.log.deprecate( win, 'runOnloadHook', $.noop, msg );
+ mw.log.deprecate( win, 'changeText', $.noop, msg );
+ mw.log.deprecate( win, 'killEvt', $.noop, msg );
+ mw.log.deprecate( win, 'addHandler', $.noop, msg );
+ mw.log.deprecate( win, 'hookEvent', $.noop, msg );
+ mw.log.deprecate( win, 'addClickHandler', $.noop, msg );
+ mw.log.deprecate( win, 'removeHandler', $.noop, msg );
+ mw.log.deprecate( win, 'getElementsByClassName', function () { return []; }, msg );
+ mw.log.deprecate( win, 'getInnerText', function () { return ''; }, msg );
+
+ // Run a function after the window onload event is fired
+ mw.log.deprecate( win, 'addOnloadHook', function ( hookFunct ) {
+ if ( onloadFuncts ) {
+ onloadFuncts.push( hookFunct );
+ } else {
+ // If func queue is gone the event has happened already,
+ // run immediately instead of queueing.
+ hookFunct();
+ }
+ }, msg );
+
+ $( win ).on( 'load', function () {
+ var i, functs;
+
+ // Don't run twice
+ if ( !onloadFuncts ) {
+ return;
+ }
+
+ // Deference and clear onloadFuncts before running any
+ // hooks to make sure we don't miss any addOnloadHook
+ // calls.
+ functs = onloadFuncts.slice();
+ onloadFuncts = undefined;
+
+ // Execute the queued functions
+ for ( i = 0; i < functs.length; i++ ) {
+ functs[i]();
+ }
+ } );
+
+ /**
+ * Toggle checkboxes with shift selection
+ *
+ * @deprecated since 1.17 Use jquery.checkboxShiftClick instead
+ */
+ msg = 'Use jquery.checkboxShiftClick instead.';
+ mw.log.deprecate( win, 'checkboxes', [], msg );
+ mw.log.deprecate( win, 'lastCheckbox', null, msg );
+ mw.log.deprecate( win, 'setupCheckboxShiftClick', $.noop, msg );
+ mw.log.deprecate( win, 'addCheckboxClickHandlers', $.noop, msg );
+ mw.log.deprecate( win, 'checkboxClickHandler', $.noop, msg );
+
+ /**
+ * Add a button to the default editor toolbar
+ *
+ * @deprecated since 1.17 Use mw.toolbar instead
+ */
+ mw.log.deprecate( win, 'mwEditButtons', [], 'Use mw.toolbar instead.' );
+ mw.log.deprecate( win, 'mwCustomEditButtons', [], 'Use mw.toolbar instead.' );
+
+ /**
+ * Spinner creation, injection and removal
+ *
+ * @deprecated since 1.18 Use jquery.spinner instead
+ */
+ mw.log.deprecate( win, 'injectSpinner', $.noop, 'Use jquery.spinner instead.' );
+ mw.log.deprecate( win, 'removeSpinner', $.noop, 'Use jquery.spinner instead.' );
+
+ /**
+ * Escape utilities
+ *
+ * @deprecated since 1.18 Use mw.html instead
+ */
+ mw.log.deprecate( win, 'escapeQuotes', $.noop, 'Use mw.html instead.' );
+ mw.log.deprecate( win, 'escapeQuotesHTML', $.noop, 'Use mw.html instead.' );
+
+ /**
+ * Display a message to the user
+ *
+ * @deprecated since 1.17 Use mediawiki.notify instead
+ * @param {string|HTMLElement} message To be put inside the message box
+ */
+ mw.log.deprecate( win, 'jsMsg', function ( message ) {
+ if ( !arguments.length || message === '' || message === null ) {
+ return true;
+ }
+ if ( typeof message !== 'object' ) {
+ message = $.parseHTML( message );
+ }
+ mw.notify( message, { autoHide: true, tag: 'legacy' } );
+ return true;
+ }, 'Use mediawiki.notify instead.' );
+
+ /**
+ * Misc. utilities
+ *
+ * @deprecated since 1.17 Use mediawiki.util or jquery.accessKeyLabel instead
+ */
+ msg = 'Use mediawiki.util instead.';
+ mw.log.deprecate( win, 'addPortletLink', mw.util.addPortletLink, msg );
+ mw.log.deprecate( win, 'appendCSS', mw.util.addCSS, msg );
+ msg = 'Use jquery.accessKeyLabel instead.';
+ mw.log.deprecate( win, 'tooltipAccessKeyPrefix', 'alt-', msg );
+ mw.log.deprecate( win, 'tooltipAccessKeyRegexp', /\[(alt-)?(.)\]$/, msg );
+ // mw.util.updateTooltipAccessKeys already generates a deprecation message.
+ win.updateTooltipAccessKeys = function () {
+ return mw.util.updateTooltipAccessKeys.apply( null, arguments );
+ };
+
+ /**
+ * Wikipage import methods
+ *
+ * See https://www.mediawiki.org/wiki/ResourceLoader/Legacy_JavaScript#wikibits.js
+ */
+
+ function importScript( page ) {
+ var uri = mw.config.get( 'wgScript' ) + '?title=' +
+ mw.util.wikiUrlencode( page ) +
+ '&action=raw&ctype=text/javascript';
+ return importScriptURI( uri );
}
-}, msg );
-
-$( win ).on( 'load', function () {
- var i, functs;
- // Don't run twice
- if ( !onloadFuncts ) {
- return;
+ /**
+ * @deprecated since 1.17 Use mw.loader instead. Warnings added in 1.25.
+ */
+ function importScriptURI( url ) {
+ if ( loadedScripts[url] ) {
+ return null;
+ }
+ loadedScripts[url] = true;
+ var s = document.createElement( 'script' );
+ s.setAttribute( 'src', url );
+ s.setAttribute( 'type', 'text/javascript' );
+ document.getElementsByTagName( 'head' )[0].appendChild( s );
+ return s;
}
- // Deference and clear onloadFuncts before running any
- // hooks to make sure we don't miss any addOnloadHook
- // calls.
- functs = onloadFuncts.slice();
- onloadFuncts = undefined;
-
- // Execute the queued functions
- for ( i = 0; i < functs.length; i++ ) {
- functs[i]();
+ function importStylesheet( page ) {
+ var uri = mw.config.get( 'wgScript' ) + '?title=' +
+ mw.util.wikiUrlencode( page ) +
+ '&action=raw&ctype=text/css';
+ return importStylesheetURI( uri );
}
-} );
-
-/**
- * Toggle checkboxes with shift selection
- *
- * @deprecated since 1.17 Use jquery.checkboxShiftClick instead
- */
-msg = 'Use jquery.checkboxShiftClick instead.';
-mw.log.deprecate( win, 'checkboxes', [], msg );
-mw.log.deprecate( win, 'lastCheckbox', null, msg );
-mw.log.deprecate( win, 'setupCheckboxShiftClick', $.noop, msg );
-mw.log.deprecate( win, 'addCheckboxClickHandlers', $.noop, msg );
-mw.log.deprecate( win, 'checkboxClickHandler', $.noop, msg );
-
-/**
- * Add a button to the default editor toolbar
- *
- * @deprecated since 1.17 Use mw.toolbar instead
- */
-mw.log.deprecate( win, 'mwEditButtons', [], 'Use mw.toolbar instead.' );
-mw.log.deprecate( win, 'mwCustomEditButtons', [], 'Use mw.toolbar instead.' );
-
-/**
- * Spinner creation, injection and removal
- *
- * @deprecated since 1.18 Use jquery.spinner instead
- */
-mw.log.deprecate( win, 'injectSpinner', $.noop, 'Use jquery.spinner instead.' );
-mw.log.deprecate( win, 'removeSpinner', $.noop, 'Use jquery.spinner instead.' );
-/**
- * Escape utilities
- *
- * @deprecated since 1.18 Use mw.html instead
- */
-mw.log.deprecate( win, 'escapeQuotes', $.noop, 'Use mw.html instead.' );
-mw.log.deprecate( win, 'escapeQuotesHTML', $.noop, 'Use mw.html instead.' );
-
-/**
- * Display a message to the user
- *
- * @deprecated since 1.17 Use mediawiki.notify instead
- * @param {string|HTMLElement} message To be put inside the message box
- */
-mw.log.deprecate( win, 'jsMsg', function ( message ) {
- if ( !arguments.length || message === '' || message === null ) {
- return true;
+ /**
+ * @deprecated since 1.17 Use mw.loader instead. Warnings added in 1.25.
+ */
+ function importStylesheetURI( url, media ) {
+ var l = document.createElement( 'link' );
+ l.rel = 'stylesheet';
+ l.href = url;
+ if ( media ) {
+ l.media = media;
+ }
+ document.getElementsByTagName( 'head' )[0].appendChild( l );
+ return l;
}
- if ( typeof message !== 'object' ) {
- message = $.parseHTML( message );
- }
- mw.notify( message, { autoHide: true, tag: 'legacy' } );
- return true;
-}, 'Use mediawiki.notify instead.' );
-
-/**
- * Misc. utilities
- *
- * @deprecated since 1.17 Use mediawiki.util or jquery.accessKeyLabel instead
- */
-msg = 'Use mediawiki.util instead.';
-mw.log.deprecate( win, 'addPortletLink', mw.util.addPortletLink, msg );
-mw.log.deprecate( win, 'appendCSS', mw.util.addCSS, msg );
-msg = 'Use jquery.accessKeyLabel instead.';
-mw.log.deprecate( win, 'tooltipAccessKeyPrefix', 'alt-', msg );
-mw.log.deprecate( win, 'tooltipAccessKeyRegexp', /\[(alt-)?(.)\]$/, msg );
-// mw.util.updateTooltipAccessKeys already generates a deprecation message.
-win.updateTooltipAccessKeys = function () {
- return mw.util.updateTooltipAccessKeys.apply( null, arguments );
-};
-
-/**
- * Wikipage import methods
- */
-// included-scripts tracker
-win.loadedScripts = {};
-
-win.importScript = function ( page ) {
- var uri = mw.config.get( 'wgScript' ) + '?title=' +
- mw.util.wikiUrlencode( page ) +
- '&action=raw&ctype=text/javascript';
- return win.importScriptURI( uri );
-};
-
-win.importScriptURI = function ( url ) {
- if ( win.loadedScripts[url] ) {
- return null;
- }
- win.loadedScripts[url] = true;
- var s = document.createElement( 'script' );
- s.setAttribute( 'src', url );
- s.setAttribute( 'type', 'text/javascript' );
- document.getElementsByTagName( 'head' )[0].appendChild( s );
- return s;
-};
-
-win.importStylesheet = function ( page ) {
- var uri = mw.config.get( 'wgScript' ) + '?title=' +
- mw.util.wikiUrlencode( page ) +
- '&action=raw&ctype=text/css';
- return win.importStylesheetURI( uri );
-};
-
-win.importStylesheetURI = function ( url, media ) {
- var l = document.createElement( 'link' );
- l.rel = 'stylesheet';
- l.href = url;
- if ( media ) {
- l.media = media;
- }
- document.getElementsByTagName('head')[0].appendChild( l );
- return l;
-};
+ msg = 'Use mw.loader instead.';
+ mw.log.deprecate( win, 'loadedScripts', loadedScripts, msg );
+ mw.log.deprecate( win, 'importScriptURI', importScriptURI, msg );
+ mw.log.deprecate( win, 'importStylesheetURI', importStylesheetURI, msg );
+ // Not quite deprecated yet.
+ win.importScript = importScript;
+ win.importStylesheet = importStylesheet;
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.less/mediawiki.mixins.less b/resources/src/mediawiki.less/mediawiki.mixins.less
index c360e1f4..3366f1e1 100644
--- a/resources/src/mediawiki.less/mediawiki.mixins.less
+++ b/resources/src/mediawiki.less/mediawiki.mixins.less
@@ -1,19 +1,26 @@
-/**
- * Common LESS mixin library for MediaWiki
- *
- * By default the folder containing this file is included in $wgResourceLoaderLESSImportPaths,
- * which makes this file importable by all less files via '@import "mediawiki.mixins";'.
- *
- * The mixins included below are considered a public interface for MediaWiki extensions.
- * The signatures of parametrized mixins should be kept as stable as possible.
- *
- * See <http://lesscss.org/#-mixins> for more information about how to write mixins.
- */
+// Common LESS mixin library for MediaWiki
+//
+// By default the folder containing this file is included in $wgResourceLoaderLESSImportPaths,
+// which makes this file importable by all less files via '@import "mediawiki.mixins";'.
+//
+// The mixins included below are considered a public interface for MediaWiki extensions.
+// The signatures of parametrized mixins should be kept as stable as possible.
+//
+// See <http://lesscss.org/#-mixins> for more information about how to write mixins.
.background-image(@url) {
background-image: e('/* @embed */') url(@url);
}
+.background-size(@width, @height) {
+ // Vendor prefix for certain older opera browsers e.g. nintendo ds
+ -o-background-size: @width @height;
+ // Vendor prefix is added to support Android 2
+ -webkit-background-size: @width @height;
+ background-size: @width @height;
+}
+
+
.vertical-gradient(@startColor: gray, @endColor: white, @startPos: 0, @endPos: 100%) {
background-color: @endColor;
background-image: -moz-linear-gradient( top, @startColor @startPos, @endColor @endPos ); // Firefox 3.6+
@@ -22,26 +29,32 @@
background-image: linear-gradient( @startColor @startPos, @endColor @endPos ); // Standard
}
-/*
- * SVG support using a transparent gradient to guarantee cross-browser
- * compatibility (browsers able to understand gradient syntax support also SVG).
- * http://pauginer.tumblr.com/post/36614680636/invisible-gradient-technique
- *
- * We use gzip compression, which means that it is okay to embed twice.
- *
- * We do not embed the fallback image on the assumption that the gain for old browsers
- * is not worth the harm done to modern ones.
- */
+// SVG support using a transparent gradient to guarantee cross-browser
+// compatibility (browsers able to understand gradient syntax support also SVG).
+// http://pauginer.tumblr.com/post/36614680636/invisible-gradient-technique
+//
+// We use gzip compression, which means that it is okay to embed twice.
+//
+// We do not embed the fallback image on the assumption that the gain for old browsers
+// is not worth the harm done to modern ones.
.background-image-svg(@svg, @fallback) {
background-image: url(@fallback);
background-image: -webkit-linear-gradient(transparent, transparent), e('/* @embed */') url(@svg);
background-image: linear-gradient(transparent, transparent), e('/* @embed */') url(@svg);
+ // Do not serve SVG to Opera 12, bad rendering with border-radius or background-size (T87504)
+ background-image: -o-linear-gradient(transparent, transparent), url(@fallback);
}
.list-style-image(@url) {
list-style-image: e('/* @embed */') url(@url);
}
+.list-style-image-svg(@svg, @fallback) {
+ list-style-image: e('/* @embed */') url(@svg);
+ /* Fallback to PNG bullet for IE 8 and below using CSS hack */
+ list-style-image: e('/* @embed */') url(@fallback)\9;
+}
+
.transition(@value) {
-webkit-transition: @value; // Safari 3.1-6.0, iOS 3.2-6.1, Android 2.1-4.3
-moz-transition: @value; // Firefox 4-15
@@ -59,3 +72,21 @@
-webkit-box-shadow: @value; // Safari 3.1-5.0, iOS 3.2-4.3, Android 2.1-3.0
box-shadow: @value; // Chrome 10+, Firefox 4+, IE 9+, Safari 5.1+, Opera 11+, iOS 5+, Android 4+
}
+
+.column-count(@value) {
+ -webkit-column-count: @value;
+ -moz-column-count: @value;
+ column-count: @value;
+}
+
+.column-width(@value) {
+ -webkit-column-width: @value;// Chrome Any, Safari 3+, Opera 11.1+
+ -moz-column-width: @value;// Firefox 1.5+
+ column-width: @value;// IE 10+
+}
+
+.column-break-inside-avoid {
+ -webkit-column-break-inside: avoid; // Chrome Any, Safari 3+, Opera 11.1+
+ page-break-inside: avoid; // Firefox 1.5+
+ break-inside: avoid-column; // IE 10+
+}
diff --git a/resources/src/mediawiki.less/mediawiki.ui/mixins.less b/resources/src/mediawiki.less/mediawiki.ui/mixins.less
index ec9888f2..2d684572 100644
--- a/resources/src/mediawiki.less/mediawiki.ui/mixins.less
+++ b/resources/src/mediawiki.less/mediawiki.ui/mixins.less
@@ -36,11 +36,16 @@
.button-colors(@bgColor) {
background: @bgColor;
- &:hover,
- &:focus {
+ &:hover {
// The inner bottom bevel should match the active background color.
box-shadow: 0 1px rgba(0, 0, 0, 10%), inset 0 -3px rgba(0, 0, 0, 20%);
border-bottom-color: mix(#000, @bgColor, 20%);
+ }
+
+ &:focus {
+ border-color: rgba(0,0,0,0.2);
+ box-shadow: inset 0 0 0 1px rgba(0,0,0,0.2);
+
outline: none;
// remove outline in Firefox
&::-moz-focus-inner {
@@ -62,6 +67,13 @@
color: @colorButtonText;
border: 1px solid @colorGray12;
+ &:hover,
+ &:active,
+ &:visited {
+ // make sure that is isn't inheriting from a general rule
+ color: @colorButtonText;
+ }
+
&:disabled {
color: @colorDisabledText;
@@ -77,16 +89,13 @@
.button-colors(@bgColor) when (lightness(@bgColor) < 70%) {
color: #fff;
// border of the same color as background so that light background and
- // dark background buttons are the same height (only top and bottom to
- // make box shadow on hover cover the corners too)
+ // dark background buttons are the same height and width
border: 1px solid @bgColor;
- border-left: none;
- border-right: none;
text-shadow: 0 1px rgba(0, 0, 0, .1);
&:disabled {
- background: @colorGray12;
- border-color: @colorGray12;
+ background: @colorGray13;
+ border-color: @colorGray13;
// make sure disabled buttons don't have hover and active states
&:hover,
@@ -104,9 +113,7 @@
&:hover,
&:focus {
- // lessphp doesn't implement tint, see above
- // color: tint(@textColor, 20%);
- color: mix(#fff, @textColor, 20%);
+ color: @textColor;
}
&:active,
diff --git a/resources/src/mediawiki.libs/CLDRPluralRuleParser.js b/resources/src/mediawiki.libs/CLDRPluralRuleParser.js
index 83c25245..31c8fef9 100644
--- a/resources/src/mediawiki.libs/CLDRPluralRuleParser.js
+++ b/resources/src/mediawiki.libs/CLDRPluralRuleParser.js
@@ -1,12 +1,13 @@
-/* This is CLDRPluralRuleParser v1.1, ported to MediaWiki ResourceLoader */
+/* This is CLDRPluralRuleParser v1.1.3, ported to MediaWiki ResourceLoader */
/**
* CLDRPluralRuleParser.js
* A parser engine for CLDR plural rules.
*
-* Copyright 2012 GPLV3+, Santhosh Thottingal
+* Copyright 2012-2014 Santhosh Thottingal and other contributors
+* Released under the MIT license
+* http://opensource.org/licenses/MIT
*
-* @version 0.1.0-alpha
* @source https://github.com/santhoshtr/CLDRPluralRuleParser
* @author Santhosh Thottingal <santhosh.thottingal@gmail.com>
* @author Timo Tijhof
@@ -22,6 +23,8 @@
*/
function pluralRuleParser(rule, number) {
+ 'use strict';
+
/*
Syntax: see http://unicode.org/reports/tr35/#Language_Plural_Rules
-----------------------------------------------------------------
@@ -44,14 +47,15 @@ function pluralRuleParser(rule, number) {
decimalValue = value ('.' value)?
*/
- // we don't evaluate the samples section of the rule. Ignore it.
+ // We don't evaluate the samples section of the rule. Ignore it.
rule = rule.split('@')[0].replace(/^\s*/, '').replace(/\s*$/, '');
if (!rule.length) {
- // empty rule or 'other' rule.
+ // Empty rule or 'other' rule.
return true;
}
- // Indicates current position in the rule as we parse through it.
+
+ // Indicates the current position in the rule as we parse through it.
// Shared among all parsing functions below.
var pos = 0,
operand,
@@ -87,15 +91,18 @@ function pluralRuleParser(rule, number) {
debug('pluralRuleParser', rule, number);
// Try parsers until one works, if none work return null
-
function choice(parserSyntax) {
return function() {
- for (var i = 0; i < parserSyntax.length; i++) {
- var result = parserSyntax[i]();
+ var i, result;
+
+ for (i = 0; i < parserSyntax.length; i++) {
+ result = parserSyntax[i]();
+
if (result !== null) {
return result;
}
}
+
return null;
};
}
@@ -103,46 +110,56 @@ function pluralRuleParser(rule, number) {
// Try several parserSyntax-es in a row.
// All must succeed; otherwise, return null.
// This is the only eager one.
-
function sequence(parserSyntax) {
- var originalPos = pos;
- var result = [];
- for (var i = 0; i < parserSyntax.length; i++) {
- var res = parserSyntax[i]();
- if (res === null) {
+ var i, parserRes,
+ originalPos = pos,
+ result = [];
+
+ for (i = 0; i < parserSyntax.length; i++) {
+ parserRes = parserSyntax[i]();
+
+ if (parserRes === null) {
pos = originalPos;
+
return null;
}
- result.push(res);
+
+ result.push(parserRes);
}
+
return result;
}
// Run the same parser over and over until it fails.
// Must succeed a minimum of n times; otherwise, return null.
-
function nOrMore(n, p) {
return function() {
- var originalPos = pos;
- var result = [];
- var parsed = p();
+ var originalPos = pos,
+ result = [],
+ parsed = p();
+
while (parsed !== null) {
result.push(parsed);
parsed = p();
}
+
if (result.length < n) {
pos = originalPos;
+
return null;
}
+
return result;
};
}
- // Helpers -- just make parserSyntax out of simpler JS builtin types
+ // Helpers - just make parserSyntax out of simpler JS builtin types
function makeStringParser(s) {
var len = s.length;
+
return function() {
var result = null;
+
if (rule.substr(pos, len) === s) {
result = s;
pos += len;
@@ -155,95 +172,122 @@ function pluralRuleParser(rule, number) {
function makeRegexParser(regex) {
return function() {
var matches = rule.substr(pos).match(regex);
+
if (matches === null) {
return null;
}
+
pos += matches[0].length;
+
return matches[0];
};
}
- /*
- * integer digits of n.
+ /**
+ * Integer digits of n.
*/
function i() {
var result = _i_();
+
if (result === null) {
debug(' -- failed i', parseInt(number, 10));
+
return result;
}
+
result = parseInt(number, 10);
debug(' -- passed i ', result);
+
return result;
}
- /*
- * absolute value of the source number (integer and decimals).
+ /**
+ * Absolute value of the source number (integer and decimals).
*/
function n() {
var result = _n_();
+
if (result === null) {
debug(' -- failed n ', number);
+
return result;
}
+
result = parseFloat(number, 10);
debug(' -- passed n ', result);
+
return result;
}
- /*
- * visible fractional digits in n, with trailing zeros.
+ /**
+ * Visible fractional digits in n, with trailing zeros.
*/
function f() {
var result = _f_();
+
if (result === null) {
debug(' -- failed f ', number);
+
return result;
}
+
result = (number + '.').split('.')[1] || 0;
debug(' -- passed f ', result);
+
return result;
}
- /*
- * visible fractional digits in n, without trailing zeros.
+ /**
+ * Visible fractional digits in n, without trailing zeros.
*/
function t() {
var result = _t_();
+
if (result === null) {
debug(' -- failed t ', number);
+
return result;
}
+
result = (number + '.').split('.')[1].replace(/0$/, '') || 0;
debug(' -- passed t ', result);
+
return result;
}
- /*
- * number of visible fraction digits in n, with trailing zeros.
+ /**
+ * Number of visible fraction digits in n, with trailing zeros.
*/
function v() {
var result = _v_();
+
if (result === null) {
debug(' -- failed v ', number);
+
return result;
}
+
result = (number + '.').split('.')[1].length || 0;
debug(' -- passed v ', result);
+
return result;
}
- /*
- * number of visible fraction digits in n, without trailing zeros.
+ /**
+ * Number of visible fraction digits in n, without trailing zeros.
*/
function w() {
var result = _w_();
+
if (result === null) {
debug(' -- failed w ', number);
+
return result;
}
+
result = (number + '.').split('.')[1].replace(/0$/, '').length || 0;
debug(' -- passed w ', result);
+
return result;
}
@@ -254,19 +298,27 @@ function pluralRuleParser(rule, number) {
expression = choice([mod, operand]);
function mod() {
- var result = sequence([operand, whitespace, choice([_mod_, _percent_]), whitespace, value]);
+ var result = sequence(
+ [operand, whitespace, choice([_mod_, _percent_]), whitespace, value]
+ );
+
if (result === null) {
debug(' -- failed mod');
+
return null;
}
+
debug(' -- passed ' + parseInt(result[0], 10) + ' ' + result[2] + ' ' + parseInt(result[4], 10));
+
return parseInt(result[0], 10) % parseInt(result[4], 10);
}
function not() {
var result = sequence([whitespace, _not_]);
+
if (result === null) {
debug(' -- failed not');
+
return null;
}
@@ -276,120 +328,170 @@ function pluralRuleParser(rule, number) {
// is_relation = expr 'is' ('not')? value
function is() {
var result = sequence([expression, whitespace, choice([_is_]), whitespace, value]);
+
if (result !== null) {
debug(' -- passed is : ' + result[0] + ' == ' + parseInt(result[4], 10));
+
return result[0] === parseInt(result[4], 10);
}
+
debug(' -- failed is');
+
return null;
}
// is_relation = expr 'is' ('not')? value
function isnot() {
- var result = sequence([expression, whitespace, choice([_isnot_, _isnot_sign_]), whitespace, value]);
+ var result = sequence(
+ [expression, whitespace, choice([_isnot_, _isnot_sign_]), whitespace, value]
+ );
+
if (result !== null) {
debug(' -- passed isnot: ' + result[0] + ' != ' + parseInt(result[4], 10));
+
return result[0] !== parseInt(result[4], 10);
}
+
debug(' -- failed isnot');
+
return null;
}
function not_in() {
- var result = sequence([expression, whitespace, _isnot_sign_, whitespace, rangeList]);
+ var i, range_list,
+ result = sequence([expression, whitespace, _isnot_sign_, whitespace, rangeList]);
+
if (result !== null) {
debug(' -- passed not_in: ' + result[0] + ' != ' + result[4]);
- var range_list = result[4];
- for (var i = 0; i < range_list.length; i++) {
+ range_list = result[4];
+
+ for (i = 0; i < range_list.length; i++) {
if (parseInt(range_list[i], 10) === parseInt(result[0], 10)) {
return false;
}
}
+
return true;
}
+
debug(' -- failed not_in');
+
return null;
}
// range_list = (range | value) (',' range_list)*
function rangeList() {
- var result = sequence([choice([range, value]), nOrMore(0, rangeTail)]);
- var resultList = [];
+ var result = sequence([choice([range, value]), nOrMore(0, rangeTail)]),
+ resultList = [];
+
if (result !== null) {
resultList = resultList.concat(result[0]);
+
if (result[1][0]) {
resultList = resultList.concat(result[1][0]);
}
+
return resultList;
}
+
debug(' -- failed rangeList');
+
return null;
}
function rangeTail() {
// ',' range_list
var result = sequence([_comma_, rangeList]);
+
if (result !== null) {
return result[1];
}
+
debug(' -- failed rangeTail');
+
return null;
}
// range = value'..'value
-
function range() {
- var i;
- var result = sequence([value, _range_, value]);
+ var i, array, left, right,
+ result = sequence([value, _range_, value]);
+
if (result !== null) {
debug(' -- passed range');
- var array = [];
- var left = parseInt(result[0], 10);
- var right = parseInt(result[2], 10);
+
+ array = [];
+ left = parseInt(result[0], 10);
+ right = parseInt(result[2], 10);
+
for (i = left; i <= right; i++) {
array.push(i);
}
+
return array;
}
+
debug(' -- failed range');
+
return null;
}
function _in() {
+ var result, range_list, i;
+
// in_relation = expr ('not')? 'in' range_list
- var result = sequence([expression, nOrMore(0, not), whitespace, choice([_in_, _equal_]), whitespace, rangeList]);
+ result = sequence(
+ [expression, nOrMore(0, not), whitespace, choice([_in_, _equal_]), whitespace, rangeList]
+ );
+
if (result !== null) {
debug(' -- passed _in:' + result);
- var range_list = result[5];
- for (var i = 0; i < range_list.length; i++) {
+
+ range_list = result[5];
+
+ for (i = 0; i < range_list.length; i++) {
if (parseInt(range_list[i], 10) === parseInt(result[0], 10)) {
return (result[1][0] !== 'not');
}
}
+
return (result[1][0] === 'not');
}
+
debug(' -- failed _in ');
+
return null;
}
- /*
- * The difference between in and within is that in only includes integers in the specified range,
- * while within includes all values.
+ /**
+ * The difference between "in" and "within" is that
+ * "in" only includes integers in the specified range,
+ * while "within" includes all values.
*/
-
function within() {
+ var range_list, result;
+
// within_relation = expr ('not')? 'within' range_list
- var result = sequence([expression, nOrMore(0, not), whitespace, _within_, whitespace, rangeList]);
+ result = sequence(
+ [expression, nOrMore(0, not), whitespace, _within_, whitespace, rangeList]
+ );
+
if (result !== null) {
debug(' -- passed within');
- var range_list = result[5];
+
+ range_list = result[5];
+
if ((result[0] >= parseInt(range_list[0], 10)) &&
(result[0] < parseInt(range_list[range_list.length - 1], 10))) {
+
return (result[1][0] !== 'not');
}
+
return (result[1][0] === 'not');
}
+
debug(' -- failed within ');
+
return null;
}
@@ -398,65 +500,83 @@ function pluralRuleParser(rule, number) {
// and_condition = relation ('and' relation)*
function and() {
- var result = sequence([relation, nOrMore(0, andTail)]);
+ var i,
+ result = sequence([relation, nOrMore(0, andTail)]);
+
if (result) {
if (!result[0]) {
return false;
}
- for (var i = 0; i < result[1].length; i++) {
+
+ for (i = 0; i < result[1].length; i++) {
if (!result[1][i]) {
return false;
}
}
+
return true;
}
+
debug(' -- failed and');
+
return null;
}
// ('and' relation)*
function andTail() {
var result = sequence([whitespace, _and_, whitespace, relation]);
+
if (result !== null) {
debug(' -- passed andTail' + result);
+
return result[3];
}
+
debug(' -- failed andTail');
+
return null;
}
// ('or' and_condition)*
function orTail() {
var result = sequence([whitespace, _or_, whitespace, and]);
+
if (result !== null) {
debug(' -- passed orTail: ' + result[3]);
+
return result[3];
}
+
debug(' -- failed orTail');
- return null;
+ return null;
}
// condition = and_condition ('or' and_condition)*
function condition() {
- var result = sequence([and, nOrMore(0, orTail)]);
+ var i,
+ result = sequence([and, nOrMore(0, orTail)]);
+
if (result) {
- for (var i = 0; i < result[1].length; i++) {
+ for (i = 0; i < result[1].length; i++) {
if (result[1][i]) {
return true;
}
}
- return result[0];
+ return result[0];
}
+
return false;
}
result = condition();
- /*
+
+ /**
* For success, the pos must have gotten to the end of the rule
* and returned a non-null.
- * n.b. This is part of language infrastructure, so we do not throw an internationalizable message.
+ * n.b. This is part of language infrastructure,
+ * so we do not throw an internationalizable message.
*/
if (result === null) {
throw new Error('Parse error at position ' + pos.toString() + ' for rule: ' + rule);
diff --git a/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.MessagePoster.js b/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.MessagePoster.js
new file mode 100644
index 00000000..91366ff5
--- /dev/null
+++ b/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.MessagePoster.js
@@ -0,0 +1,38 @@
+/*global OO*/
+( function ( mw ) {
+ /**
+ * This is the abstract base class for MessagePoster implementations.
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {mw.Title} title Title to post to
+ */
+ mw.messagePoster.MessagePoster = function MwMessagePoster() {};
+
+ OO.initClass( mw.messagePoster.MessagePoster );
+
+ /**
+ * Post a message (with subject and body) to a talk page.
+ *
+ * @param {string} subject Subject/topic title; plaintext only (no wikitext or HTML)
+ * @param {string} body Body, as wikitext. Signature code will automatically be added
+ * by MessagePosters that require one, unless the message already contains the string
+ * ~~~.
+ * @return {jQuery.Promise} Promise completing when the post succeeds or fails.
+ * For failure, will be rejected with three arguments:
+ *
+ * - primaryError - Primary error code. For a mw.Api failure,
+ * this should be 'api-fail'.
+ * - secondaryError - Secondary error code. For a mw.Api failure,
+ * this, should be mw.Api's code, e.g. 'http', 'ok-but-empty', or the error passed through
+ * from the server.
+ * - details - Further details about the error
+ *
+ * @localdoc
+ * The base class currently does nothing, but could be used for shared analytics or
+ * something.
+ */
+ mw.messagePoster.MessagePoster.prototype.post = function () {};
+}( mediaWiki ) );
diff --git a/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.WikitextMessagePoster.js b/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.WikitextMessagePoster.js
new file mode 100644
index 00000000..296576b4
--- /dev/null
+++ b/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.WikitextMessagePoster.js
@@ -0,0 +1,53 @@
+/*global OO*/
+( function ( mw, $ ) {
+ /**
+ * This is an implementation of MessagePoster for wikitext talk pages.
+ *
+ * @class mw.messagePoster.WikitextMessagePoster
+ * @extends mw.messagePoster.MessagePoster
+ *
+ * @constructor
+ * @param {mw.Title} title Wikitext page in a talk namespace, to post to
+ */
+ function WikitextMessagePoster( title ) {
+ this.api = new mw.Api();
+ this.title = title;
+ }
+
+ OO.inheritClass(
+ WikitextMessagePoster,
+ mw.messagePoster.MessagePoster
+ );
+
+ /**
+ * @inheritdoc
+ */
+ WikitextMessagePoster.prototype.post = function ( subject, body ) {
+ mw.messagePoster.WikitextMessagePoster.parent.prototype.post.call( this, subject, body );
+
+ // Add signature if needed
+ if ( body.indexOf( '~~~' ) === -1 ) {
+ body += '\n\n~~~~';
+ }
+
+ return this.api.newSection(
+ this.title,
+ subject,
+ body,
+ { redirect: true }
+ ).then( function ( resp, jqXHR ) {
+ if ( resp.edit.result === 'Success' ) {
+ return $.Deferred().resolve( resp, jqXHR );
+ } else {
+ // mediawiki.api.js checks for resp.error. Are there actually cases where the
+ // request fails, but it's not caught there?
+ return $.Deferred().reject( 'api-unexpected' );
+ }
+ }, function ( code, details ) {
+ return $.Deferred().reject( 'api-fail', code, details );
+ } ).promise();
+ };
+
+ mw.messagePoster.factory.register( 'wikitext', WikitextMessagePoster );
+ mw.messagePoster.WikitextMessagePoster = WikitextMessagePoster;
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.factory.js b/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.factory.js
new file mode 100644
index 00000000..9d280800
--- /dev/null
+++ b/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.factory.js
@@ -0,0 +1,109 @@
+/*global OO*/
+( function ( mw, $ ) {
+ /**
+ * This is a factory for MessagePoster objects, which allows a pluggable to way to script leaving a
+ * talk page message.
+ *
+ * @class mw.messagePoster.factory
+ * @singleton
+ */
+ function MwMessagePosterFactory() {
+ this.api = new mw.Api();
+ this.contentModelToClass = {};
+ }
+
+ OO.initClass( MwMessagePosterFactory );
+
+ // Note: This registration scheme is currently not compatible with LQT, since that doesn't
+ // have its own content model, just islqttalkpage. LQT pages will be passed to the wikitext
+ // MessagePoster.
+ /**
+ * Registers a MessagePoster subclass for a given content model.
+ *
+ * @param {string} contentModel Content model of pages this MessagePoster can post to
+ * @param {Function} messagePosterConstructor Constructor for MessagePoster
+ */
+ MwMessagePosterFactory.prototype.register = function ( contentModel, messagePosterConstructor ) {
+ if ( this.contentModelToClass[contentModel] !== undefined ) {
+ throw new Error( 'The content model \'' + contentModel + '\' is already registered.' );
+ }
+
+ this.contentModelToClass[contentModel] = messagePosterConstructor;
+ };
+
+ /**
+ * Unregisters a given content model
+ * This is exposed for testing and should not normally be needed.
+ *
+ * @param {string} contentModel Content model to unregister
+ */
+ MwMessagePosterFactory.prototype.unregister = function ( contentModel ) {
+ delete this.contentModelToClass[contentModel];
+ };
+
+ /**
+ * Creates a MessagePoster, given a title. A promise for this is returned.
+ * This works by determining the content model, then loading the corresponding
+ * module (which will register the MessagePoster class), and finally constructing it.
+ *
+ * This does not require the message and should be called as soon as possible, so it does the
+ * API and ResourceLoader requests in the background.
+ *
+ * @param {mw.Title} title Title that will be posted to
+ * @return {jQuery.Promise} Promise resolving to a mw.messagePoster.MessagePoster.
+ * For failure, rejected with up to three arguments:
+ *
+ * - errorCode Error code string
+ * - error Error explanation
+ * - details Further error details
+ */
+ MwMessagePosterFactory.prototype.create = function ( title ) {
+ var pageId, page, contentModel, moduleName,
+ factory = this;
+
+ return this.api.get( {
+ action: 'query',
+ prop: 'info',
+ indexpageids: 1,
+ titles: title.getPrefixedDb()
+ } ).then( function ( result ) {
+ if ( result.query.pageids.length > 0 ) {
+ pageId = result.query.pageids[0];
+ page = result.query.pages[pageId];
+
+ contentModel = page.contentmodel;
+ moduleName = 'mediawiki.messagePoster.' + contentModel;
+ return mw.loader.using( moduleName ).then( function () {
+ return factory.createForContentModel(
+ contentModel,
+ title
+ );
+ }, function () {
+ return $.Deferred().reject( 'failed-to-load-module', 'Failed to load the \'' + moduleName + '\' module' );
+ } );
+ } else {
+ return $.Deferred().reject( 'unexpected-response', 'Unexpected API response' );
+ }
+ }, function ( errorCode, details ) {
+ return $.Deferred().reject( 'content-model-query-failed', errorCode, details );
+ } ).promise();
+ };
+
+ /**
+ * Creates a MessagePoster instance, given a title and content model
+ *
+ * @private
+ *
+ * @param {string} contentModel Content model of title
+ * @param {mw.Title} title Title being posted to
+ * @return {mw.messagePoster.MessagePoster}
+ *
+ */
+ MwMessagePosterFactory.prototype.createForContentModel = function ( contentModel, title ) {
+ return new this.contentModelToClass[contentModel]( title );
+ };
+
+ mw.messagePoster = {
+ factory: new MwMessagePosterFactory()
+ };
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.page/mediawiki.page.gallery.js b/resources/src/mediawiki.page/mediawiki.page.gallery.js
index 1892967a..95140704 100644
--- a/resources/src/mediawiki.page/mediawiki.page.gallery.js
+++ b/resources/src/mediawiki.page/mediawiki.page.gallery.js
@@ -2,211 +2,266 @@
* Show gallery captions when focused. Copied directly from jquery.mw-jump.js.
* Also Dynamically resize images to justify them.
*/
-( function ( $ ) {
- $( function () {
- var isTouchScreen,
- gettingFocus,
- galleries = 'ul.mw-gallery-packed-overlay, ul.mw-gallery-packed-hover, ul.mw-gallery-packed';
-
+( function ( mw, $ ) {
+ var $galleries,
+ bound = false,
// Is there a better way to detect a touchscreen? Current check taken from stack overflow.
- isTouchScreen = !!( window.ontouchstart !== undefined || window.DocumentTouch !== undefined && document instanceof window.DocumentTouch );
+ isTouchScreen = !!( window.ontouchstart !== undefined ||
+ window.DocumentTouch !== undefined && document instanceof window.DocumentTouch
+ );
- if ( isTouchScreen ) {
- // Always show the caption for a touch screen.
- $( 'ul.mw-gallery-packed-hover' )
- .addClass( 'mw-gallery-packed-overlay' )
- .removeClass( 'mw-gallery-packed-hover' );
- } else {
- // Note use of just "a", not a.image, since we want this to trigger if a link in
- // the caption receives focus
- $( 'ul.mw-gallery-packed-hover li.gallerybox' ).on( 'focus blur', 'a', function ( e ) {
- // Confusingly jQuery leaves e.type as focusout for delegated blur events
- gettingFocus = e.type !== 'blur' && e.type !== 'focusout';
- $( this ).closest( 'li.gallerybox' ).toggleClass( 'mw-gallery-focused', gettingFocus );
- } );
- }
+ /**
+ * Perform the layout justification.
+ * @ignore
+ * @context {HTMLElement} A `ul.mw-gallery-*` element
+ */
+ function justify() {
+ var lastTop,
+ $img,
+ imgWidth,
+ imgHeight,
+ captionWidth,
+ rows = [],
+ $gallery = $( this );
- // Now on to justification.
- // We may still get ragged edges if someone resizes their window. Could bind to
- // that event, otoh do we really want to constantly be resizing galleries?
- $( galleries ).each( function () {
- var lastTop,
- $img,
- imgWidth,
- imgHeight,
- rows = [],
- $gallery = $( this );
-
- $gallery.children( 'li' ).each( function () {
- // Math.floor to be paranoid if things are off by 0.00000000001
- var top = Math.floor( $( this ).position().top ),
- $this = $( this );
-
- if ( top !== lastTop ) {
- rows[rows.length] = [];
- lastTop = top;
- }
+ $gallery.children( 'li' ).each( function () {
+ // Math.floor to be paranoid if things are off by 0.00000000001
+ var top = Math.floor( $( this ).position().top ),
+ $this = $( this );
- $img = $this.find( 'div.thumb a.image img' );
- if ( $img.length && $img[0].height ) {
- imgHeight = $img[0].height;
- imgWidth = $img[0].width;
- } else {
- // If we don't have a real image, get the containing divs width/height.
- // Note that if we do have a real image, using this method will generally
- // give the same answer, but can be different in the case of a very
- // narrow image where extra padding is added.
- imgHeight = $this.children().children( 'div:first' ).height();
- imgWidth = $this.children().children( 'div:first' ).width();
- }
+ if ( top !== lastTop ) {
+ rows[rows.length] = [];
+ lastTop = top;
+ }
- // Hack to make an edge case work ok
- if ( imgHeight < 30 ) {
- // Don't try and resize this item.
- imgHeight = 0;
- }
+ $img = $this.find( 'div.thumb a.image img' );
+ if ( $img.length && $img[0].height ) {
+ imgHeight = $img[0].height;
+ imgWidth = $img[0].width;
+ } else {
+ // If we don't have a real image, get the containing divs width/height.
+ // Note that if we do have a real image, using this method will generally
+ // give the same answer, but can be different in the case of a very
+ // narrow image where extra padding is added.
+ imgHeight = $this.children().children( 'div:first' ).height();
+ imgWidth = $this.children().children( 'div:first' ).width();
+ }
- rows[rows.length - 1][rows[rows.length - 1].length] = {
- $elm: $this,
- width: $this.outerWidth(),
- imgWidth: imgWidth,
- // XXX: can divide by 0 ever happen?
- aspect: imgWidth / imgHeight,
- captionWidth: $this.children().children( 'div.gallerytextwrapper' ).width(),
- height: imgHeight
- };
- } );
+ // Hack to make an edge case work ok
+ if ( imgHeight < 30 ) {
+ // Don't try and resize this item.
+ imgHeight = 0;
+ }
- ( function () {
- var maxWidth,
- combinedAspect,
- combinedPadding,
- curRow,
- curRowHeight,
- wantedWidth,
- preferredHeight,
- newWidth,
- padding,
- $outerDiv,
- $innerDiv,
- $imageDiv,
- $imageElm,
- imageElm,
- $caption,
- i,
- j,
- avgZoom,
- totalZoom = 0;
-
- for ( i = 0; i < rows.length; i++ ) {
- maxWidth = $gallery.width();
- combinedAspect = 0;
- combinedPadding = 0;
- curRow = rows[i];
- curRowHeight = 0;
-
- for ( j = 0; j < curRow.length; j++ ) {
- if ( curRowHeight === 0 ) {
- if ( isFinite( curRow[j].height ) ) {
- // Get the height of this row, by taking the first
- // non-out of bounds height
- curRowHeight = curRow[j].height;
- }
- }
+ captionWidth = $this.children().children( 'div.gallerytextwrapper' ).width();
+ rows[rows.length - 1][rows[rows.length - 1].length] = {
+ $elm: $this,
+ width: $this.outerWidth(),
+ imgWidth: imgWidth,
+ // XXX: can divide by 0 ever happen?
+ aspect: imgWidth / imgHeight,
+ captionWidth: captionWidth,
+ height: imgHeight
+ };
- if ( curRow[j].aspect === 0 || !isFinite( curRow[j].aspect ) ) {
- // One of the dimensions are 0. Probably should
- // not try to resize.
- combinedPadding += curRow[j].width;
- } else {
- combinedAspect += curRow[j].aspect;
- combinedPadding += curRow[j].width - curRow[j].imgWidth;
- }
- }
+ // Save all boundaries so we can restore them on window resize
+ $this.data( 'imgWidth', imgWidth );
+ $this.data( 'imgHeight', imgHeight );
+ $this.data( 'width', $this.outerWidth() );
+ $this.data( 'captionWidth', captionWidth );
+ } );
- // Add some padding for inter-element spacing.
- combinedPadding += 5 * curRow.length;
- wantedWidth = maxWidth - combinedPadding;
- preferredHeight = wantedWidth / combinedAspect;
-
- if ( preferredHeight > curRowHeight * 1.5 ) {
- // Only expand at most 1.5 times current size
- // As that's as high a resolution as we have.
- // Also on the off chance there is a bug in this
- // code, would prevent accidentally expanding to
- // be 10 billion pixels wide.
- if ( i === rows.length - 1 ) {
- // If its the last row, and we can't fit it,
- // don't make the entire row huge.
- avgZoom = ( totalZoom / ( rows.length - 1 ) ) * curRowHeight;
- if ( isFinite( avgZoom ) && avgZoom >= 1 && avgZoom <= 1.5 ) {
- preferredHeight = avgZoom;
- } else {
- // Probably a single row gallery
- preferredHeight = curRowHeight;
- }
- } else {
- preferredHeight = 1.5 * curRowHeight;
+ ( function () {
+ var maxWidth,
+ combinedAspect,
+ combinedPadding,
+ curRow,
+ curRowHeight,
+ wantedWidth,
+ preferredHeight,
+ newWidth,
+ padding,
+ $outerDiv,
+ $innerDiv,
+ $imageDiv,
+ $imageElm,
+ imageElm,
+ $caption,
+ i,
+ j,
+ avgZoom,
+ totalZoom = 0;
+
+ for ( i = 0; i < rows.length; i++ ) {
+ maxWidth = $gallery.width();
+ combinedAspect = 0;
+ combinedPadding = 0;
+ curRow = rows[i];
+ curRowHeight = 0;
+
+ for ( j = 0; j < curRow.length; j++ ) {
+ if ( curRowHeight === 0 ) {
+ if ( isFinite( curRow[j].height ) ) {
+ // Get the height of this row, by taking the first
+ // non-out of bounds height
+ curRowHeight = curRow[j].height;
}
}
- if ( !isFinite( preferredHeight ) ) {
- // This *definitely* should not happen.
- // Skip this row.
- continue;
- }
- if ( preferredHeight < 5 ) {
- // Well something clearly went wrong...
- // Skip this row.
- continue;
- }
- if ( preferredHeight / curRowHeight > 1 ) {
- totalZoom += preferredHeight / curRowHeight;
+ if ( curRow[j].aspect === 0 || !isFinite( curRow[j].aspect ) ) {
+ // One of the dimensions are 0. Probably should
+ // not try to resize.
+ combinedPadding += curRow[j].width;
} else {
- // If we shrink, still consider that a zoom of 1
- totalZoom += 1;
+ combinedAspect += curRow[j].aspect;
+ combinedPadding += curRow[j].width - curRow[j].imgWidth;
}
+ }
- for ( j = 0; j < curRow.length; j++ ) {
- newWidth = preferredHeight * curRow[j].aspect;
- padding = curRow[j].width - curRow[j].imgWidth;
- $outerDiv = curRow[j].$elm;
- $innerDiv = $outerDiv.children( 'div' ).first();
- $imageDiv = $innerDiv.children( 'div.thumb' );
- $imageElm = $imageDiv.find( 'img' ).first();
- imageElm = $imageElm.length ? $imageElm[0] : null;
- $caption = $outerDiv.find( 'div.gallerytextwrapper' );
-
- // Since we are going to re-adjust the height, the vertical
- // centering margins need to be reset.
- $imageDiv.children( 'div' ).css( 'margin', '0px auto' );
-
- if ( newWidth < 60 || !isFinite( newWidth ) ) {
- // Making something skinnier than this will mess up captions,
- if ( newWidth < 1 || !isFinite( newWidth ) ) {
- $innerDiv.height( preferredHeight );
- // Don't even try and touch the image size if it could mean
- // making it disappear.
- continue;
- }
+ // Add some padding for inter-element spacing.
+ combinedPadding += 5 * curRow.length;
+ wantedWidth = maxWidth - combinedPadding;
+ preferredHeight = wantedWidth / combinedAspect;
+
+ if ( preferredHeight > curRowHeight * 1.5 ) {
+ // Only expand at most 1.5 times current size
+ // As that's as high a resolution as we have.
+ // Also on the off chance there is a bug in this
+ // code, would prevent accidentally expanding to
+ // be 10 billion pixels wide.
+ if ( i === rows.length - 1 ) {
+ // If its the last row, and we can't fit it,
+ // don't make the entire row huge.
+ avgZoom = ( totalZoom / ( rows.length - 1 ) ) * curRowHeight;
+ if ( isFinite( avgZoom ) && avgZoom >= 1 && avgZoom <= 1.5 ) {
+ preferredHeight = avgZoom;
} else {
- $outerDiv.width( newWidth + padding );
- $innerDiv.width( newWidth + padding );
- $imageDiv.width( newWidth );
- $caption.width( curRow[j].captionWidth + ( newWidth - curRow[j].imgWidth ) );
+ // Probably a single row gallery
+ preferredHeight = curRowHeight;
}
+ } else {
+ preferredHeight = 1.5 * curRowHeight;
+ }
+ }
+ if ( !isFinite( preferredHeight ) ) {
+ // This *definitely* should not happen.
+ // Skip this row.
+ continue;
+ }
+ if ( preferredHeight < 5 ) {
+ // Well something clearly went wrong...
+ // Skip this row.
+ continue;
+ }
- if ( imageElm ) {
- // We don't always have an img, e.g. in the case of an invalid file.
- imageElm.width = newWidth;
- imageElm.height = preferredHeight;
- } else {
- // Not a file box.
- $imageDiv.height( preferredHeight );
+ if ( preferredHeight / curRowHeight > 1 ) {
+ totalZoom += preferredHeight / curRowHeight;
+ } else {
+ // If we shrink, still consider that a zoom of 1
+ totalZoom += 1;
+ }
+
+ for ( j = 0; j < curRow.length; j++ ) {
+ newWidth = preferredHeight * curRow[j].aspect;
+ padding = curRow[j].width - curRow[j].imgWidth;
+ $outerDiv = curRow[j].$elm;
+ $innerDiv = $outerDiv.children( 'div' ).first();
+ $imageDiv = $innerDiv.children( 'div.thumb' );
+ $imageElm = $imageDiv.find( 'img' ).first();
+ imageElm = $imageElm.length ? $imageElm[0] : null;
+ $caption = $outerDiv.find( 'div.gallerytextwrapper' );
+
+ // Since we are going to re-adjust the height, the vertical
+ // centering margins need to be reset.
+ $imageDiv.children( 'div' ).css( 'margin', '0px auto' );
+
+ if ( newWidth < 60 || !isFinite( newWidth ) ) {
+ // Making something skinnier than this will mess up captions,
+ if ( newWidth < 1 || !isFinite( newWidth ) ) {
+ $innerDiv.height( preferredHeight );
+ // Don't even try and touch the image size if it could mean
+ // making it disappear.
+ continue;
}
+ } else {
+ $outerDiv.width( newWidth + padding );
+ $innerDiv.width( newWidth + padding );
+ $imageDiv.width( newWidth );
+ $caption.width( curRow[j].captionWidth + ( newWidth - curRow[j].imgWidth ) );
+ }
+
+ if ( imageElm ) {
+ // We don't always have an img, e.g. in the case of an invalid file.
+ imageElm.width = newWidth;
+ imageElm.height = preferredHeight;
+ } else {
+ // Not a file box.
+ $imageDiv.height( preferredHeight );
}
}
- }() );
+ }
+ }() );
+ }
+
+ function handleResizeStart() {
+ $galleries.children( 'li' ).each( function () {
+ var imgWidth = $( this ).data( 'imgWidth' ),
+ imgHeight = $( this ).data( 'imgHeight' ),
+ width = $( this ).data( 'width' ),
+ captionWidth = $( this ).data( 'captionWidth' ),
+ $innerDiv = $( this ).children( 'div' ).first(),
+ $imageDiv = $innerDiv.children( 'div.thumb' ),
+ $imageElm, imageElm;
+
+ // Restore original sizes so we can arrange the elements as on freshly loaded page
+ $( this ).width( width );
+ $innerDiv.width( width );
+ $imageDiv.width( imgWidth );
+ $( this ).find( 'div.gallerytextwrapper' ).width( captionWidth );
+
+ $imageElm = $( this ).find( 'img' ).first();
+ imageElm = $imageElm.length ? $imageElm[0] : null;
+ if ( imageElm ) {
+ imageElm.width = imgWidth;
+ imageElm.height = imgHeight;
+ } else {
+ $imageDiv.height( imgHeight );
+ }
+ } );
+ }
+
+ function handleResizeEnd() {
+ $galleries.each( justify );
+ }
+
+ mw.hook( 'wikipage.content' ).add( function ( $content ) {
+ if ( isTouchScreen ) {
+ // Always show the caption for a touch screen.
+ $content.find( 'ul.mw-gallery-packed-hover' )
+ .addClass( 'mw-gallery-packed-overlay' )
+ .removeClass( 'mw-gallery-packed-hover' );
+ } else {
+ // Note use of just "a", not a.image, since we want this to trigger if a link in
+ // the caption receives focus
+ $content.find( 'ul.mw-gallery-packed-hover li.gallerybox' ).on( 'focus blur', 'a', function ( e ) {
+ // Confusingly jQuery leaves e.type as focusout for delegated blur events
+ var gettingFocus = e.type !== 'blur' && e.type !== 'focusout';
+ $( this ).closest( 'li.gallerybox' ).toggleClass( 'mw-gallery-focused', gettingFocus );
+ } );
+ }
+
+ $galleries = $content.find( 'ul.mw-gallery-packed-overlay, ul.mw-gallery-packed-hover, ul.mw-gallery-packed' );
+ // Call the justification asynchronous because live preview fires the hook with detached $content.
+ setTimeout( function () {
+ $galleries.each( justify );
+
+ // Bind here instead of in the top scope as the callbacks use $galleries.
+ if ( !bound ) {
+ bound = true;
+ $( window )
+ .resize( $.debounce( 300, true, handleResizeStart ) )
+ .resize( $.debounce( 300, handleResizeEnd ) );
+ }
} );
} );
-}( jQuery ) );
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.page/mediawiki.page.image.pagination.js b/resources/src/mediawiki.page/mediawiki.page.image.pagination.js
index 622e818d..9ad9c30a 100644
--- a/resources/src/mediawiki.page/mediawiki.page.image.pagination.js
+++ b/resources/src/mediawiki.page/mediawiki.page.image.pagination.js
@@ -2,23 +2,66 @@
* Implement AJAX navigation for multi-page images so the user may browse without a full page reload.
*/
( function ( mw, $ ) {
- var jqXhr, $multipageimage, $spinner;
+ var jqXhr, $multipageimage, $spinner,
+ cache = {},
+ cacheOrder = [];
- /* Fetch the next page and use jQuery to swap the table.multipageimage contents.
+ /* Fetch the next page, caching up to 10 last-loaded pages.
* @param {string} url
- * @param {boolean} [hist=false] Whether this is a load triggered by history navigation (if
- * true, this function won't push a new history state, for the browser did so already).
+ * @return {jQuery.Promise}
*/
- function loadPage( url, hist ) {
- var $tr;
- if ( jqXhr ) {
+ function fetchPageData( url ) {
+ if ( jqXhr && jqXhr.abort ) {
// Prevent race conditions and piling up pending requests
jqXhr.abort();
- jqXhr = undefined;
}
+ jqXhr = undefined;
+
+ // Try the cache
+ if ( cache[url] ) {
+ // Update access freshness
+ cacheOrder.splice( $.inArray( url, cacheOrder ), 1 );
+ cacheOrder.push( url );
+ return $.Deferred().resolve( cache[url] ).promise();
+ }
+
+ // @todo Don't fetch the entire page. Ideally we'd only fetch the content portion or the data
+ // (thumbnail urls) and update the interface manually.
+ jqXhr = $.ajax( url ).then( function ( data ) {
+ return $( data ).find( 'table.multipageimage' ).contents();
+ } );
- // Add a new spinner if one doesn't already exist
- if ( !$spinner ) {
+ // Handle cache updates
+ jqXhr.done( function ( $contents ) {
+ jqXhr = undefined;
+
+ // Cache the newly loaded page
+ cache[url] = $contents;
+ cacheOrder.push( url );
+
+ // Remove the oldest entry if we're over the limit
+ if ( cacheOrder.length > 10 ) {
+ delete cache[ cacheOrder[0] ];
+ cacheOrder = cacheOrder.slice( 1 );
+ }
+ } );
+
+ return jqXhr.promise();
+ }
+
+ /* Fetch the next page and use jQuery to swap the table.multipageimage contents.
+ * @param {string} url
+ * @param {boolean} [hist=false] Whether this is a load triggered by history navigation (if
+ * true, this function won't push a new history state, for the browser did so already).
+ */
+ function switchPage( url, hist ) {
+ var $tr, promise;
+
+ // Start fetching data (might be cached)
+ promise = fetchPageData( url );
+
+ // Add a new spinner if one doesn't already exist and the data is not already ready
+ if ( !$spinner && promise.state() !== 'resolved' ) {
$tr = $multipageimage.find( 'tr' );
$spinner = $.createSpinner( {
size: 'large',
@@ -34,13 +77,11 @@
$multipageimage.empty().append( $spinner );
}
- // @todo Don't fetch the entire page. Ideally we'd only fetch the content portion or the data
- // (thumbnail urls) and update the interface manually.
- jqXhr = $.ajax( url ).done( function ( data ) {
- jqXhr = $spinner = undefined;
+ promise.done( function ( $contents ) {
+ $spinner = undefined;
// Replace table contents
- $multipageimage.empty().append( $( data ).find( 'table.multipageimage' ).contents() );
+ $multipageimage.empty().append( $contents.clone() );
bindPageNavigation( $multipageimage );
@@ -66,12 +107,12 @@
.extend( { title: mw.config.get( 'wgPageName' ), page: page } )
.toString();
- loadPage( uri );
+ switchPage( uri );
e.preventDefault();
} );
$container.find( 'form[name="pageselector"]' ).one( 'change submit', function ( e ) {
- loadPage( this.action + '?' + $( this ).serialize() );
+ switchPage( this.action + '?' + $( this ).serialize() );
e.preventDefault();
} );
}
@@ -93,7 +134,7 @@
$( window ).on( 'popstate', function ( e ) {
var state = e.originalEvent.state;
if ( state && state.tag === 'mw-pagination' ) {
- loadPage( location.href, true );
+ switchPage( location.href, true );
}
} );
}
diff --git a/resources/src/mediawiki.page/mediawiki.page.ready.js b/resources/src/mediawiki.page/mediawiki.page.ready.js
index 246cc817..36eb9d4f 100644
--- a/resources/src/mediawiki.page/mediawiki.page.ready.js
+++ b/resources/src/mediawiki.page/mediawiki.page.ready.js
@@ -7,7 +7,7 @@
// it works only comparing to window.self or window.window (http://stackoverflow.com/q/4850978/319266)
if ( window.top !== window.self ) {
// Un-trap us from framesets
- window.top.location = window.location;
+ window.top.location.href = location.href;
}
}
diff --git a/resources/src/mediawiki.page/mediawiki.page.startup.js b/resources/src/mediawiki.page/mediawiki.page.startup.js
index 4aae6069..ddd4f0c4 100644
--- a/resources/src/mediawiki.page/mediawiki.page.startup.js
+++ b/resources/src/mediawiki.page/mediawiki.page.startup.js
@@ -4,7 +4,7 @@
// Client profile classes for <html>
// Allows for easy hiding/showing of JS or no-JS-specific UI elements
- $( 'html' )
+ $( document.documentElement )
.addClass( 'client-js' )
.removeClass( 'client-nojs' );
diff --git a/resources/src/mediawiki.skinning/content.css b/resources/src/mediawiki.skinning/content.css
index 7a417081..7dd5ee7f 100644
--- a/resources/src/mediawiki.skinning/content.css
+++ b/resources/src/mediawiki.skinning/content.css
@@ -8,7 +8,8 @@
/* Table of Contents */
#toc,
.toc,
-.mw-warning {
+.mw-warning,
+.toccolours {
border: 1px solid #aaa;
background-color: #f9f9f9;
padding: 5px;
@@ -87,13 +88,6 @@ table.toc td {
font-size: 94%;
}
-.toccolours {
- border: 1px solid #aaa;
- background-color: #f9f9f9;
- padding: 5px;
- font-size: 95%;
-}
-
/* Warning */
.mw-warning {
margin-left: 50px;
@@ -165,8 +159,13 @@ div.magnify a {
width: 15px;
height: 11px;
/* Default styles when there's no .mw-content-ltr or .mw-content-rtl, overridden below */
+
+ /* Use same SVG support hack as mediawiki.legacy's shared.css */
+ background-image: url(images/magnify-clip-ltr.png);
+ /* @embed */
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
/* @embed */
- background: url(images/magnify-clip-ltr.png) center center no-repeat;
+ background-image: linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
/* Don't annoy people who copy-paste everything too much */
-moz-user-select: none;
-webkit-user-select: none;
@@ -194,8 +193,12 @@ img.thumbborder {
/* @noflip */
.mw-content-ltr div.magnify a {
- /* @embed */
+ /* Use same SVG support hack as mediawiki.legacy's shared.css */
background-image: url(images/magnify-clip-ltr.png);
+ /* @embed */
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
+ /* @embed */
+ background-image: linear-gradient(transparent, transparent), url(images/magnify-clip-ltr.svg);
}
/* @noflip */
@@ -212,8 +215,12 @@ img.thumbborder {
/* @noflip */
.mw-content-rtl div.magnify a {
- /* @embed */
+ /* Use same SVG support hack as mediawiki.legacy's shared.css */
background-image: url(images/magnify-clip-rtl.png);
+ /* @embed */
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/magnify-clip-rtl.svg);
+ /* @embed */
+ background-image: linear-gradient(transparent, transparent), url(images/magnify-clip-rtl.svg);
}
/* @noflip */
diff --git a/resources/src/mediawiki.skinning/elements.css b/resources/src/mediawiki.skinning/elements.css
index 392a2a66..8140d1a5 100644
--- a/resources/src/mediawiki.skinning/elements.css
+++ b/resources/src/mediawiki.skinning/elements.css
@@ -112,7 +112,7 @@ h6 {
}
h3 {
- font-size: 132%;
+ font-size: 128%;
}
h4 {
@@ -141,7 +141,6 @@ h5 {
p {
margin: .4em 0 .5em 0;
- line-height: 1.5em;
}
p img {
@@ -149,14 +148,12 @@ p img {
}
ul {
- line-height: 1.5em;
list-style-type: square;
margin: .3em 0 0 1.6em;
padding: 0;
}
ol {
- line-height: 1.5em;
margin: .3em 0 0 3.2em;
padding: 0;
list-style-image: none;
@@ -177,17 +174,10 @@ dl {
}
dd {
- line-height: 1.5em;
margin-left: 1.6em;
margin-bottom: .1em;
}
-/* IE 6 and 7 lack support for quotes aroud the <q> element ('::before' and '::after'
- pseudoelements, 'quotes' property). Let's italicize it instead (using the star hack). */
-q {
- *font-style: italic;
-}
-
pre, code, tt, kbd, samp, .mw-code {
/*
* Some browsers will render the monospace text too small, namely Firefox, Chrome and Safari.
@@ -221,7 +211,6 @@ fieldset {
border: 1px solid #2f6fab;
margin: 1em 0 1em 0;
padding: 0 1em 1em;
- line-height: 1.5em;
}
fieldset.nested {
diff --git a/resources/src/mediawiki.skinning/images/magnify-clip-ltr.png b/resources/src/mediawiki.skinning/images/magnify-clip-ltr.png
index 00a9cee1..712b1b48 100644
--- a/resources/src/mediawiki.skinning/images/magnify-clip-ltr.png
+++ b/resources/src/mediawiki.skinning/images/magnify-clip-ltr.png
Binary files differ
diff --git a/resources/src/mediawiki.skinning/images/magnify-clip-ltr.svg b/resources/src/mediawiki.skinning/images/magnify-clip-ltr.svg
new file mode 100644
index 00000000..4d3dcb65
--- /dev/null
+++ b/resources/src/mediawiki.skinning/images/magnify-clip-ltr.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 15" width="15" height="11">
+ <g id="magnify-clip" fill="#fff" stroke="#000">
+ <path id="bigbox" d="M1.509 1.865h10.99v7.919h-10.99z"/>
+ <path id="smallbox" d="M-1.499 6.868h5.943v4.904h-5.943z"/>
+ </g>
+</svg>
diff --git a/resources/src/mediawiki.skinning/images/magnify-clip-rtl.png b/resources/src/mediawiki.skinning/images/magnify-clip-rtl.png
index ff85c077..1d03a8c0 100644
--- a/resources/src/mediawiki.skinning/images/magnify-clip-rtl.png
+++ b/resources/src/mediawiki.skinning/images/magnify-clip-rtl.png
Binary files differ
diff --git a/resources/src/mediawiki.skinning/images/magnify-clip-rtl.svg b/resources/src/mediawiki.skinning/images/magnify-clip-rtl.svg
new file mode 100644
index 00000000..582e4ae7
--- /dev/null
+++ b/resources/src/mediawiki.skinning/images/magnify-clip-rtl.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 11 15" width="15" height="11">
+ <g id="magnify-clip" fill="#fff" stroke="#000">
+ <path id="bigbox" d="M9.491 1.865h-10.99v7.919h10.99z"/>
+ <path id="smallbox" d="M12.499 6.868h-5.943v4.904h5.943z"/>
+ </g>
+</svg>
diff --git a/resources/src/mediawiki.skinning/interface.css b/resources/src/mediawiki.skinning/interface.css
index 398a132d..b57ee367 100644
--- a/resources/src/mediawiki.skinning/interface.css
+++ b/resources/src/mediawiki.skinning/interface.css
@@ -15,6 +15,14 @@
clear: both;
}
+.editOptions {
+ background-color: #F0F0F0;
+ border: 1px solid silver;
+ border-top: none;
+ padding: 1em 1em 1.5em 1em;
+ margin-bottom: 2em;
+}
+
.usermessage {
background-color: #ffce7b;
border: 1px solid #ffa500;
diff --git a/resources/src/mediawiki.special/mediawiki.special.block.js b/resources/src/mediawiki.special/mediawiki.special.block.js
index 8579e054..aca335ee 100644
--- a/resources/src/mediawiki.special/mediawiki.special.block.js
+++ b/resources/src/mediawiki.special/mediawiki.special.block.js
@@ -12,7 +12,7 @@
function updateBlockOptions( instant ) {
var blocktarget = $.trim( $blockTarget.val() ),
isEmpty = blocktarget === '',
- isIp = mw.util.isIPv4Address( blocktarget, true ) || mw.util.isIPv6Address( blocktarget, true ),
+ isIp = mw.util.isIPAddress( blocktarget, true ),
isIpRange = isIp && blocktarget.match( /\/\d+$/ );
if ( isIp && !isEmpty ) {
diff --git a/resources/src/mediawiki.special/mediawiki.special.changeslist.css b/resources/src/mediawiki.special/mediawiki.special.changeslist.css
index c92db167..16fdf38a 100644
--- a/resources/src/mediawiki.special/mediawiki.special.changeslist.css
+++ b/resources/src/mediawiki.special/mediawiki.special.changeslist.css
@@ -5,3 +5,11 @@
.mw-changeslist-line-watched .mw-title {
font-weight: bold;
}
+
+/*
+ * Titles, including username links, are especially prone for getting jumbled up
+ * with other titles, usernames, etc. in mixed RTL-LTR environment.
+ */
+.mw-changeslist .mw-title {
+ unicode-bidi: embed;
+}
diff --git a/resources/src/mediawiki.special/mediawiki.special.changeslist.legend.css b/resources/src/mediawiki.special/mediawiki.special.changeslist.legend.css
index 6b0bf991..14f6aeee 100644
--- a/resources/src/mediawiki.special/mediawiki.special.changeslist.legend.css
+++ b/resources/src/mediawiki.special/mediawiki.special.changeslist.legend.css
@@ -20,10 +20,14 @@
.mw-changeslist-legend dt {
float: left;
- margin-right: 0.5em;
+ margin: 0 0.5em 0 0;
}
.mw-changeslist-legend dd {
margin-left: 1.5em;
+}
+
+.mw-changeslist-legend dt,
+.mw-changeslist-legend dd {
line-height: 1.3em;
}
diff --git a/resources/src/mediawiki.special/mediawiki.special.css b/resources/src/mediawiki.special/mediawiki.special.css
index 0356fc74..d2457262 100644
--- a/resources/src/mediawiki.special/mediawiki.special.css
+++ b/resources/src/mediawiki.special/mediawiki.special.css
@@ -118,3 +118,8 @@ table.mw-userrights-groups * td,
table.mw-userrights-groups * th {
padding-right: 1.5em;
}
+
+/* Special:Contributions */
+.mw-contributions-form select {
+ vertical-align: middle;
+}
diff --git a/resources/src/mediawiki.special/mediawiki.special.edittags.css b/resources/src/mediawiki.special/mediawiki.special.edittags.css
new file mode 100644
index 00000000..204009c9
--- /dev/null
+++ b/resources/src/mediawiki.special/mediawiki.special.edittags.css
@@ -0,0 +1,15 @@
+/*!
+ * Styling for Special:EditTags and action=editchangetags
+ */
+#mw-edittags-tags-selector td {
+ vertical-align: top;
+}
+
+#mw-edittags-tags-selector-multi td {
+ vertical-align: top;
+ padding-right: 1.5em;
+}
+
+#mw-edittags-tag-list {
+ min-width: 20em;
+}
diff --git a/resources/src/mediawiki.special/mediawiki.special.edittags.js b/resources/src/mediawiki.special/mediawiki.special.edittags.js
new file mode 100644
index 00000000..69a2a67a
--- /dev/null
+++ b/resources/src/mediawiki.special/mediawiki.special.edittags.js
@@ -0,0 +1,24 @@
+/*!
+ * JavaScript for Special:EditTags
+ */
+( function ( mw, $ ) {
+ $( function () {
+ var $tagList = $( '#mw-edittags-tag-list' );
+ if ( $tagList.length ) {
+ $tagList.chosen( {
+ /*jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
+ placeholder_text_multiple: mw.msg( 'tags-edit-chosen-placeholder' ),
+ no_results_text: mw.msg( 'tags-edit-chosen-no-results' )
+ } );
+ }
+
+ $( '#mw-edittags-remove-all' ).on( 'change', function ( e ) {
+ $( '.mw-edittags-remove-checkbox' ).prop( 'checked', e.target.checked );
+ } );
+ $( '.mw-edittags-remove-checkbox' ).on( 'change', function ( e ) {
+ if ( !e.target.checked ) {
+ $( '#mw-edittags-remove-all' ).prop( 'checked', false );
+ }
+ } );
+ } );
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.special/mediawiki.special.import.js b/resources/src/mediawiki.special/mediawiki.special.import.js
index a9a985eb..5622b32a 100644
--- a/resources/src/mediawiki.special/mediawiki.special.import.js
+++ b/resources/src/mediawiki.special/mediawiki.special.import.js
@@ -2,7 +2,7 @@
* JavaScript for Special:Import
*/
( function ( $ ) {
- function updateImportSubprojectList() {
+ function updateImportSubprojectList( firstTime ) {
var $projectField = $( '#mw-import-table-interwiki #interwiki' ),
$subprojectField = $projectField.parent().find( '#subproject' ),
$selected = $projectField.find( ':selected' ),
@@ -14,7 +14,7 @@
option = document.createElement( 'option' );
option.appendChild( document.createTextNode( el ) );
option.setAttribute( 'value', el );
- if ( oldValue === el ) {
+ if ( oldValue === el && firstTime !== true ) {
option.setAttribute( 'selected', 'selected' );
}
return option;
@@ -29,7 +29,7 @@
var $projectField = $( '#mw-import-table-interwiki #interwiki' );
if ( $projectField.length ) {
$projectField.change( updateImportSubprojectList );
- updateImportSubprojectList();
+ updateImportSubprojectList( true );
}
} );
}( jQuery ) );
diff --git a/resources/src/mediawiki.special/mediawiki.special.pageLanguage.js b/resources/src/mediawiki.special/mediawiki.special.pageLanguage.js
index ba7f7342..7c2269fa 100644
--- a/resources/src/mediawiki.special/mediawiki.special.pageLanguage.js
+++ b/resources/src/mediawiki.special/mediawiki.special.pageLanguage.js
@@ -6,4 +6,4 @@
$( '#mw-pl-options-2' ).prop( 'checked', true );
} );
} );
-} ( jQuery ) );
+}( jQuery ) );
diff --git a/resources/src/mediawiki.special/mediawiki.special.preferences.js b/resources/src/mediawiki.special/mediawiki.special.preferences.js
index 1f6429b2..4bd747b2 100644
--- a/resources/src/mediawiki.special/mediawiki.special.preferences.js
+++ b/resources/src/mediawiki.special/mediawiki.special.preferences.js
@@ -5,15 +5,18 @@ jQuery( function ( $ ) {
var $preftoc, $preferences, $fieldsets, $legends,
hash, labelFunc,
$tzSelect, $tzTextbox, $localtimeHolder, servertime,
- $checkBoxes, savedWindowOnBeforeUnload;
+ $checkBoxes, allowCloseWindowFn;
labelFunc = function () {
return this.id.replace( /^mw-prefsection/g, 'preftab' );
};
$( '#prefsubmit' ).attr( 'id', 'prefcontrol' );
- $preftoc = $( '<ul id="preftoc"></ul>' )
- .attr( 'role', 'tablist' );
+ $preftoc = $( '<ul>' )
+ .attr( {
+ id: 'preftoc',
+ role: 'tablist'
+ } );
$preferences = $( '#preferences' )
.addClass( 'jsprefs' )
.before( $preftoc );
@@ -41,7 +44,7 @@ jQuery( function ( $ ) {
} else {
$( this ).css( 'height', 'auto' );
}
- } ).insertBefore( $preftoc );
+ } ).insertBefore( $preftoc );
/**
* It uses document.getElementById for security reasons (HTML injections in $()).
@@ -57,7 +60,7 @@ jQuery( function ( $ ) {
// therefore save and restore scrollTop to prevent jumping.
scrollTop = $( window ).scrollTop();
if ( mode !== 'noHash' ) {
- window.location.hash = '#mw-prefsection-' + name;
+ location.hash = '#mw-prefsection-' + name;
}
$( window ).scrollTop( scrollTop );
@@ -127,7 +130,7 @@ jQuery( function ( $ ) {
// If we've reloaded the page or followed an open-in-new-window,
// make the selected tab visible.
- hash = window.location.hash;
+ hash = location.hash;
if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
}
@@ -142,7 +145,7 @@ jQuery( function ( $ ) {
( document.documentMode === undefined || document.documentMode >= 8 )
) {
$( window ).on( 'hashchange', function () {
- var hash = window.location.hash;
+ var hash = location.hash;
if ( hash.match( /^#mw-prefsection-[\w\-]+/ ) ) {
switchPrefTab( hash.replace( '#mw-prefsection-', '' ) );
} else if ( hash === '' ) {
@@ -223,12 +226,8 @@ jQuery( function ( $ ) {
localTime = servertime + minuteDiff;
// Bring time within the [0,1440) range.
- while ( localTime < 0 ) {
- localTime += 1440;
- }
- while ( localTime >= 1440 ) {
- localTime -= 1440;
- }
+ localTime = ( ( localTime % 1440 ) + 1440 ) % 1440;
+
$localtimeHolder.text( mediaWiki.language.convertNumber( minutesToHours( localTime ) ) );
}
@@ -267,39 +266,14 @@ jQuery( function ( $ ) {
// Set up a message to notify users if they try to leave the page without
// saving.
$( '#mw-prefs-form' ).data( 'origdata', $( '#mw-prefs-form' ).serialize() );
- $( window )
- .on( 'beforeunload.prefswarning', function () {
- var retval;
-
- // Check if anything changed
- if ( $( '#mw-prefs-form' ).serialize() !== $( '#mw-prefs-form' ).data( 'origdata' ) ) {
- // Return our message
- retval = mediaWiki.msg( 'prefswarning-warning', mediaWiki.msg( 'saveprefs' ) );
- }
+ allowCloseWindowFn = mediaWiki.confirmCloseWindow( {
+ test: function () {
+ return $( '#mw-prefs-form' ).serialize() !== $( '#mw-prefs-form' ).data( 'origdata' );
+ },
- // Unset the onbeforeunload handler so we don't break page caching in Firefox
- savedWindowOnBeforeUnload = window.onbeforeunload;
- window.onbeforeunload = null;
- if ( retval !== undefined ) {
- // ...but if the user chooses not to leave the page, we need to rebind it
- setTimeout( function () {
- window.onbeforeunload = savedWindowOnBeforeUnload;
- }, 1 );
- return retval;
- }
- } )
- .on( 'pageshow.prefswarning', function () {
- // Re-add onbeforeunload handler
- if ( !window.onbeforeunload ) {
- window.onbeforeunload = savedWindowOnBeforeUnload;
- }
- } );
- $( '#mw-prefs-form' ).submit( function () {
- // Unbind our beforeunload handler
- $( window ).off( '.prefswarning' );
- } );
- $( '#mw-prefs-restoreprefs' ).click( function () {
- // Unbind our beforeunload handler
- $( window ).off( '.prefswarning' );
+ message: mediaWiki.msg( 'prefswarning-warning', mediaWiki.msg( 'saveprefs' ) ),
+ namespace: 'prefswarning'
} );
+ $( '#mw-prefs-form' ).submit( allowCloseWindowFn );
+ $( '#mw-prefs-restoreprefs' ).click( allowCloseWindowFn );
} );
diff --git a/resources/src/mediawiki.special/mediawiki.special.search.css b/resources/src/mediawiki.special/mediawiki.special.search.css
index ef955077..8f845dfa 100644
--- a/resources/src/mediawiki.special/mediawiki.special.search.css
+++ b/resources/src/mediawiki.special/mediawiki.special.search.css
@@ -40,34 +40,34 @@ div.searchresult {
color: green;
font-size: 97%;
}
-.mw-search-formheader {
+.mw-search-profile-tabs {
background-color: #f3f3f3;
margin-top: 1em;
border: 1px solid silver;
}
-.mw-search-formheader div.search-types {
+.mw-search-profile-tabs div.search-types {
float: left;
padding-left: 0.25em;
}
-.mw-search-formheader div.search-types ul {
+.mw-search-profile-tabs div.search-types ul {
margin: 0 !important;
padding: 0 !important;
list-style: none !important;
}
-.mw-search-formheader div.search-types ul li {
+.mw-search-profile-tabs div.search-types ul li {
float: left;
margin: 0;
padding: 0;
}
-.mw-search-formheader div.search-types ul li a {
+.mw-search-profile-tabs div.search-types ul li a {
display: block;
padding: 0.5em;
}
-.mw-search-formheader div.search-types ul li.current a {
+.mw-search-profile-tabs div.search-types ul li.current a {
color: #333333;
cursor: default;
}
-.mw-search-formheader div.search-types ul li.current a:hover {
+.mw-search-profile-tabs div.search-types ul li.current a:hover {
text-decoration: none;
}
#mw-search-top-table div.results-info {
@@ -106,9 +106,10 @@ fieldset#mw-searchoptions div#mw-search-togglebox input {
fieldset#mw-searchoptions table {
float: left;
margin-right: 3em;
+ border-collapse: collapse;
}
fieldset#mw-searchoptions table td {
- padding-right: 1em;
+ padding: 0 1em 0 0;
white-space: nowrap;
}
fieldset#mw-searchoptions div.divider {
diff --git a/resources/src/mediawiki.special/mediawiki.special.upload.js b/resources/src/mediawiki.special/mediawiki.special.upload.js
index 286befcc..eeccda59 100644
--- a/resources/src/mediawiki.special/mediawiki.special.upload.js
+++ b/resources/src/mediawiki.special/mediawiki.special.upload.js
@@ -6,8 +6,9 @@
* @singleton
*/
( function ( mw, $ ) {
- var ajaxUploadDestCheck = mw.config.get( 'wgAjaxUploadDestCheck' ),
- $license = $( '#wpLicense' ), uploadWarning, uploadLicense;
+ var uploadWarning, uploadLicense,
+ ajaxUploadDestCheck = mw.config.get( 'wgAjaxUploadDestCheck' ),
+ $license = $( '#wpLicense' );
window.wgUploadWarningObj = uploadWarning = {
responseCache: { '': '&nbsp;' },
@@ -136,11 +137,6 @@
};
$( function () {
- // Disable URL box if the URL copy upload source type is not selected
- if ( !$( '#wpSourceTypeurl' ).prop( 'checked' ) ) {
- $( '#wpUploadFileURL' ).prop( 'disabled', true );
- }
-
// AJAX wpDestFile warnings
if ( ajaxUploadDestCheck ) {
// Insert an event handler that fetches upload warnings when wpDestFile
@@ -202,6 +198,7 @@
// URLs are less likely to have a useful extension, so don't include them in the
// extension check.
if (
+ mw.config.get( 'wgCheckFileExtensions' ) &&
mw.config.get( 'wgStrictFileExtensions' ) &&
mw.config.get( 'wgFileExtensions' ) &&
$( this ).attr( 'id' ) !== 'wpUploadFileURL'
@@ -294,12 +291,7 @@
ctx,
meta,
previewSize = 180,
- thumb = $( '<div id="mw-upload-thumbnail" class="thumb tright">' +
- '<div class="thumbinner">' +
- '<div class="mw-small-spinner" style="width: 180px; height: 180px"></div>' +
- '<div class="thumbcaption"><div class="filename"></div><div class="fileinfo"></div></div>' +
- '</div>' +
- '</div>' );
+ thumb = mw.template.get( 'mediawiki.special.upload', 'thumbnail.html' ).render();
thumb.find( '.filename' ).text( file.name ).end()
.find( '.fileinfo' ).text( prettySize( file.size ) ).end();
@@ -387,10 +379,11 @@
};
img.src = dataURL;
}, mw.config.get( 'wgFileCanRotate' ) ? function ( data ) {
- /*jshint camelcase:false, nomen:false */
try {
meta = mw.libs.jpegmeta( data, file.fileName );
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers, disallowDanglingUnderscores
meta._binary_data = null;
+ // jscs:enable
} catch ( e ) {
meta = null;
}
@@ -534,32 +527,58 @@
// Disable all upload source fields except the selected one
$( function () {
- var i, $row,
- $rows = $( '.mw-htmlform-field-UploadSourceField' );
+ var $rows = $( '.mw-htmlform-field-UploadSourceField' );
- /**
- * @param {jQuery} $currentRow
- * @return {Function} Handler
- * @return {jQuery.Event} return.e
- */
- function createHandler( $currentRow ) {
- return function () {
- $( '.mw-upload-source-error' ).remove();
- if ( this.checked ) {
- // Disable all inputs
- $rows.find( 'input[name!="wpSourceType"]' ).prop( 'disabled', true );
- // Re-enable the current one
- $currentRow.find( 'input' ).prop( 'disabled', false );
- }
- };
- }
+ $rows.on( 'change', 'input[type="radio"]', function ( e ) {
+ var currentRow = e.delegateTarget;
+
+ if ( !this.checked ) {
+ return;
+ }
+
+ $( '.mw-upload-source-error' ).remove();
+
+ // Enable selected upload method
+ $( currentRow ).find( 'input' ).prop( 'disabled', false );
- for ( i = $rows.length; i; i-- ) {
- $row = $rows.eq( i - 1 );
- $row
- .find( 'input[name="wpSourceType"]' )
- .change( createHandler( $row ) );
+ // Disable inputs of other upload methods
+ // (except for the radio button to re-enable it)
+ $rows
+ .not( currentRow )
+ .find( 'input[type!="radio"]' )
+ .prop( 'disabled', true );
+ } );
+
+ // Set initial state
+ if ( !$( '#wpSourceTypeurl' ).prop( 'checked' ) ) {
+ $( '#wpUploadFileURL' ).prop( 'disabled', true );
}
} );
+ $( function () {
+ // Prevent losing work
+ var allowCloseWindow,
+ $uploadForm = $( '#mw-upload-form' );
+
+ if ( !mw.user.options.get( 'useeditwarning' ) ) {
+ // If the user doesn't want edit warnings, don't set things up.
+ return;
+ }
+
+ $uploadForm.data( 'origtext', $uploadForm.serialize() );
+
+ allowCloseWindow = mw.confirmCloseWindow( {
+ test: function () {
+ return $( '#wpUploadFile' ).get( 0 ).files.length !== 0 ||
+ $uploadForm.data( 'origtext' ) !== $uploadForm.serialize();
+ },
+
+ message: mw.msg( 'editwarning-warning' ),
+ namespace: 'uploadwarning'
+ } );
+
+ $uploadForm.submit( function () {
+ allowCloseWindow();
+ } );
+ } );
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.special/mediawiki.special.userlogin.common.css b/resources/src/mediawiki.special/mediawiki.special.userlogin.common.css
index 28b14462..30f000bf 100644
--- a/resources/src/mediawiki.special/mediawiki.special.userlogin.common.css
+++ b/resources/src/mediawiki.special/mediawiki.special.userlogin.common.css
@@ -1,5 +1,5 @@
/* Styles for user login and signup forms */
-#mw-userlogin-help {
+.mw-form-related-link-container {
text-align: center;
}
diff --git a/resources/src/mediawiki.special/mediawiki.special.userlogin.common.js b/resources/src/mediawiki.special/mediawiki.special.userlogin.common.js
index 247f8141..f5289dee 100644
--- a/resources/src/mediawiki.special/mediawiki.special.userlogin.common.js
+++ b/resources/src/mediawiki.special/mediawiki.special.userlogin.common.js
@@ -20,7 +20,7 @@
if ( !$submit.length ) {
return;
}
- tabIndex = $submit.prop( 'tabindex' ) - 1;
+ tabIndex = $submit.prop( 'tabIndex' ) - 1;
$captchaStuff = $content.find( '.captcha' );
if ( $captchaStuff.length ) {
diff --git a/resources/src/mediawiki.special/mediawiki.special.userlogin.login.css b/resources/src/mediawiki.special/mediawiki.special.userlogin.login.css
index 64471b27..df3db574 100644
--- a/resources/src/mediawiki.special/mediawiki.special.userlogin.login.css
+++ b/resources/src/mediawiki.special/mediawiki.special.userlogin.login.css
@@ -7,16 +7,3 @@
margin: 0 auto;
padding-top: 4em;
}
-
-#mw-createaccount-cta,
-#mw-createaccount-another {
- font-size: 0.9em;
- font-weight: normal;
- text-align: center;
-}
-
-#mw-createaccount-join {
- margin-left: 0.75em;
- width: auto;
- display: inline-block;
-}
diff --git a/resources/src/mediawiki.special/mediawiki.special.userlogin.signup.js b/resources/src/mediawiki.special/mediawiki.special.userlogin.signup.js
index 68d3f61b..a32a7902 100644
--- a/resources/src/mediawiki.special/mediawiki.special.userlogin.signup.js
+++ b/resources/src/mediawiki.special/mediawiki.special.userlogin.signup.js
@@ -135,6 +135,6 @@
} );
}
- $input.on( events, $.debounce( 250, updateUsernameStatus ) );
+ $input.on( events, $.debounce( 1000, updateUsernameStatus ) );
} );
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.special/mediawiki.special.version.css b/resources/src/mediawiki.special/mediawiki.special.version.css
index 764e3777..7c87d68f 100644
--- a/resources/src/mediawiki.special/mediawiki.special.version.css
+++ b/resources/src/mediawiki.special/mediawiki.special.version.css
@@ -12,3 +12,7 @@
th.mw-version-ext-col-label {
font-size: 0.9em;
}
+
+.mw-version-ext-vcs-version {
+ unicode-bidi: embed;
+}
diff --git a/resources/src/mediawiki.special/templates/thumbnail.html b/resources/src/mediawiki.special/templates/thumbnail.html
new file mode 100644
index 00000000..73042f24
--- /dev/null
+++ b/resources/src/mediawiki.special/templates/thumbnail.html
@@ -0,0 +1,9 @@
+<div id="mw-upload-thumbnail" class="thumb tright">
+ <div class="thumbinner">
+ <div class="mw-small-spinner" style="width: 180px; height: 180px"></div>
+ <div class="thumbcaption">
+ <div class="filename"></div>
+ <div class="fileinfo"></div>
+ </div>
+ </div>
+</div>
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_bold.png b/resources/src/mediawiki.toolbar/images/ar/button_bold.png
index e524f6cb..e524f6cb 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_bold.png
+++ b/resources/src/mediawiki.toolbar/images/ar/button_bold.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_headline.png b/resources/src/mediawiki.toolbar/images/ar/button_headline.png
index 398e5614..398e5614 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_headline.png
+++ b/resources/src/mediawiki.toolbar/images/ar/button_headline.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_italic.png b/resources/src/mediawiki.toolbar/images/ar/button_italic.png
index 6ec73e9e..6ec73e9e 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_italic.png
+++ b/resources/src/mediawiki.toolbar/images/ar/button_italic.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_link.png b/resources/src/mediawiki.toolbar/images/ar/button_link.png
index c9c63f6c..c9c63f6c 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_link.png
+++ b/resources/src/mediawiki.toolbar/images/ar/button_link.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_nowiki.png b/resources/src/mediawiki.toolbar/images/ar/button_nowiki.png
index 743ea61b..743ea61b 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ar/button_nowiki.png
+++ b/resources/src/mediawiki.toolbar/images/ar/button_nowiki.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/be-tarask/button_bold.png b/resources/src/mediawiki.toolbar/images/be-tarask/button_bold.png
index 5c10cfe2..5c10cfe2 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/be-tarask/button_bold.png
+++ b/resources/src/mediawiki.toolbar/images/be-tarask/button_bold.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/be-tarask/button_italic.png b/resources/src/mediawiki.toolbar/images/be-tarask/button_italic.png
index 72209d74..72209d74 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/be-tarask/button_italic.png
+++ b/resources/src/mediawiki.toolbar/images/be-tarask/button_italic.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/be-tarask/button_link.png b/resources/src/mediawiki.toolbar/images/be-tarask/button_link.png
index 09c86fb1..09c86fb1 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/be-tarask/button_link.png
+++ b/resources/src/mediawiki.toolbar/images/be-tarask/button_link.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/de/button_bold.png b/resources/src/mediawiki.toolbar/images/de/button_bold.png
index 367d5bc1..367d5bc1 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/de/button_bold.png
+++ b/resources/src/mediawiki.toolbar/images/de/button_bold.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/de/button_italic.png b/resources/src/mediawiki.toolbar/images/de/button_italic.png
index fdd8c9f9..fdd8c9f9 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/de/button_italic.png
+++ b/resources/src/mediawiki.toolbar/images/de/button_italic.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_bold.png b/resources/src/mediawiki.toolbar/images/en/button_bold.png
index 75c3f109..75c3f109 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_bold.png
+++ b/resources/src/mediawiki.toolbar/images/en/button_bold.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_extlink.png b/resources/src/mediawiki.toolbar/images/en/button_extlink.png
index 458943c1..458943c1 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_extlink.png
+++ b/resources/src/mediawiki.toolbar/images/en/button_extlink.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_headline.png b/resources/src/mediawiki.toolbar/images/en/button_headline.png
index 9cf751d9..9cf751d9 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_headline.png
+++ b/resources/src/mediawiki.toolbar/images/en/button_headline.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_hr.png b/resources/src/mediawiki.toolbar/images/en/button_hr.png
index 47e1ca40..47e1ca40 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_hr.png
+++ b/resources/src/mediawiki.toolbar/images/en/button_hr.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_image.png b/resources/src/mediawiki.toolbar/images/en/button_image.png
index 69192965..69192965 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_image.png
+++ b/resources/src/mediawiki.toolbar/images/en/button_image.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_italic.png b/resources/src/mediawiki.toolbar/images/en/button_italic.png
index 527fbd14..527fbd14 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_italic.png
+++ b/resources/src/mediawiki.toolbar/images/en/button_italic.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_link.png b/resources/src/mediawiki.toolbar/images/en/button_link.png
index eb5634b9..eb5634b9 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_link.png
+++ b/resources/src/mediawiki.toolbar/images/en/button_link.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_media.png b/resources/src/mediawiki.toolbar/images/en/button_media.png
index 4194ec18..4194ec18 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_media.png
+++ b/resources/src/mediawiki.toolbar/images/en/button_media.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_nowiki.png b/resources/src/mediawiki.toolbar/images/en/button_nowiki.png
index 2ba818de..2ba818de 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_nowiki.png
+++ b/resources/src/mediawiki.toolbar/images/en/button_nowiki.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_sig.png b/resources/src/mediawiki.toolbar/images/en/button_sig.png
index fe34b3fb..fe34b3fb 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/en/button_sig.png
+++ b/resources/src/mediawiki.toolbar/images/en/button_sig.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_bold.png b/resources/src/mediawiki.toolbar/images/fa/button_bold.png
index c54d094c..c54d094c 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_bold.png
+++ b/resources/src/mediawiki.toolbar/images/fa/button_bold.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_headline.png b/resources/src/mediawiki.toolbar/images/fa/button_headline.png
index 9890d155..9890d155 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_headline.png
+++ b/resources/src/mediawiki.toolbar/images/fa/button_headline.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_italic.png b/resources/src/mediawiki.toolbar/images/fa/button_italic.png
index 33f91ed6..33f91ed6 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_italic.png
+++ b/resources/src/mediawiki.toolbar/images/fa/button_italic.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_link.png b/resources/src/mediawiki.toolbar/images/fa/button_link.png
index 76b939e6..76b939e6 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_link.png
+++ b/resources/src/mediawiki.toolbar/images/fa/button_link.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_nowiki.png b/resources/src/mediawiki.toolbar/images/fa/button_nowiki.png
index 743ea61b..743ea61b 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/fa/button_nowiki.png
+++ b/resources/src/mediawiki.toolbar/images/fa/button_nowiki.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ksh/LICENSE b/resources/src/mediawiki.toolbar/images/ksh/LICENSE
index 47ecfe4e..47ecfe4e 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ksh/LICENSE
+++ b/resources/src/mediawiki.toolbar/images/ksh/LICENSE
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ksh/button_italic.png b/resources/src/mediawiki.toolbar/images/ksh/button_italic.png
index 15496c08..15496c08 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ksh/button_italic.png
+++ b/resources/src/mediawiki.toolbar/images/ksh/button_italic.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/LICENSE b/resources/src/mediawiki.toolbar/images/ru/LICENSE
index bedcec66..bedcec66 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/LICENSE
+++ b/resources/src/mediawiki.toolbar/images/ru/LICENSE
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/button_bold.png b/resources/src/mediawiki.toolbar/images/ru/button_bold.png
index eae30d98..eae30d98 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/button_bold.png
+++ b/resources/src/mediawiki.toolbar/images/ru/button_bold.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/button_italic.png b/resources/src/mediawiki.toolbar/images/ru/button_italic.png
index b958d220..b958d220 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/button_italic.png
+++ b/resources/src/mediawiki.toolbar/images/ru/button_italic.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/button_link.png b/resources/src/mediawiki.toolbar/images/ru/button_link.png
index 12ad3731..12ad3731 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/images/ru/button_link.png
+++ b/resources/src/mediawiki.toolbar/images/ru/button_link.png
Binary files differ
diff --git a/resources/src/mediawiki.toolbar/toolbar.js b/resources/src/mediawiki.toolbar/toolbar.js
new file mode 100644
index 00000000..70d54ce3
--- /dev/null
+++ b/resources/src/mediawiki.toolbar/toolbar.js
@@ -0,0 +1,202 @@
+/**
+ * Interface for the classic edit toolbar.
+ *
+ * @class mw.toolbar
+ * @singleton
+ */
+( function ( mw, $ ) {
+ var toolbar, isReady, $toolbar, queue, slice, $currentFocused;
+
+ /**
+ * Internal helper that does the actual insertion of the button into the toolbar.
+ *
+ * For backwards-compatibility, passing `imageFile`, `speedTip`, `tagOpen`, `tagClose`,
+ * `sampleText` and `imageId` as separate arguments (in this order) is also supported.
+ *
+ * @private
+ *
+ * @param {Object} button Object with the following properties.
+ * You are required to provide *either* the `onClick` parameter, or the three parameters
+ * `tagOpen`, `tagClose` and `sampleText`, but not both (they're mutually exclusive).
+ * @param {string} [button.imageFile] Image to use for the button.
+ * @param {string} button.speedTip Tooltip displayed when user mouses over the button.
+ * @param {Function} [button.onClick] Function to be executed when the button is clicked.
+ * @param {string} [button.tagOpen]
+ * @param {string} [button.tagClose]
+ * @param {string} [button.sampleText] Alternative to `onClick`. `tagOpen`, `tagClose` and
+ * `sampleText` together provide the markup that should be inserted into page text at
+ * current cursor position.
+ * @param {string} [button.imageId] `id` attribute of the button HTML element. Can be
+ * used to define the image with CSS if it's not provided as `imageFile`.
+ */
+ function insertButton( button, speedTip, tagOpen, tagClose, sampleText, imageId ) {
+ var $button;
+
+ // Backwards compatibility
+ if ( typeof button !== 'object' ) {
+ button = {
+ imageFile: button,
+ speedTip: speedTip,
+ tagOpen: tagOpen,
+ tagClose: tagClose,
+ sampleText: sampleText,
+ imageId: imageId
+ };
+ }
+
+ if ( button.imageFile ) {
+ $button = $( '<img>' ).attr( {
+ src: button.imageFile,
+ alt: button.speedTip,
+ title: button.speedTip,
+ id: button.imageId || undefined,
+ 'class': 'mw-toolbar-editbutton'
+ } );
+ } else {
+ $button = $( '<div>' ).attr( {
+ title: button.speedTip,
+ id: button.imageId || undefined,
+ 'class': 'mw-toolbar-editbutton'
+ } );
+ }
+
+ $button.click( function ( e ) {
+ if ( button.onClick !== undefined ) {
+ button.onClick( e );
+ } else {
+ toolbar.insertTags( button.tagOpen, button.tagClose, button.sampleText );
+ }
+
+ return false;
+ } );
+
+ $toolbar.append( $button );
+ }
+
+ isReady = false;
+ $toolbar = false;
+
+ /**
+ * @private
+ * @property {Array}
+ * Contains button objects (and for backwards compatibilty, it can
+ * also contains an arguments array for insertButton).
+ */
+ queue = [];
+ slice = queue.slice;
+
+ toolbar = {
+
+ /**
+ * Add buttons to the toolbar.
+ *
+ * Takes care of race conditions and time-based dependencies by placing buttons in a queue if
+ * this method is called before the toolbar is created.
+ *
+ * For backwards-compatibility, passing `imageFile`, `speedTip`, `tagOpen`, `tagClose`,
+ * `sampleText` and `imageId` as separate arguments (in this order) is also supported.
+ *
+ * @inheritdoc #insertButton
+ */
+ addButton: function () {
+ if ( isReady ) {
+ insertButton.apply( toolbar, arguments );
+ } else {
+ // Convert arguments list to array
+ queue.push( slice.call( arguments ) );
+ }
+ },
+
+ /**
+ * Add multiple buttons to the toolbar (see also #addButton).
+ *
+ * Example usage:
+ *
+ * addButtons( [ { .. }, { .. }, { .. } ] );
+ * addButtons( { .. }, { .. } );
+ *
+ * @param {Object|Array...} [buttons] An array of button objects or the first
+ * button object in a list of variadic arguments.
+ */
+ addButtons: function ( buttons ) {
+ if ( !$.isArray( buttons ) ) {
+ buttons = slice.call( arguments );
+ }
+ if ( isReady ) {
+ $.each( buttons, function () {
+ insertButton( this );
+ } );
+ } else {
+ // Push each button into the queue
+ queue.push.apply( queue, buttons );
+ }
+ },
+
+ /**
+ * Apply tagOpen/tagClose to selection in currently focused textarea.
+ *
+ * Uses `sampleText` if selection is empty.
+ *
+ * @param {string} tagOpen
+ * @param {string} tagClose
+ * @param {string} sampleText
+ */
+ insertTags: function ( tagOpen, tagClose, sampleText ) {
+ if ( $currentFocused && $currentFocused.length ) {
+ $currentFocused.textSelection(
+ 'encapsulateSelection', {
+ pre: tagOpen,
+ peri: sampleText,
+ post: tagClose
+ }
+ );
+ }
+ }
+ };
+
+ // Legacy (for compatibility with the code previously in skins/common.edit.js)
+ mw.log.deprecate( window, 'addButton', toolbar.addButton, 'Use mw.toolbar.addButton instead.' );
+ mw.log.deprecate( window, 'insertTags', toolbar.insertTags, 'Use mw.toolbar.insertTags instead.' );
+
+ // For backwards compatibility. Used to be called from EditPage.php, maybe other places as well.
+ mw.log.deprecate( toolbar, 'init', $.noop );
+
+ // Expose API publicly
+ mw.toolbar = toolbar;
+
+ $( function () {
+ var i, button;
+
+ // Used to determine where to insert tags
+ $currentFocused = $( '#wpTextbox1' );
+
+ // Populate the selector cache for $toolbar
+ $toolbar = $( '#toolbar' );
+
+ for ( i = 0; i < queue.length; i++ ) {
+ button = queue[i];
+ if ( $.isArray( button ) ) {
+ // Forwarded arguments array from mw.toolbar.addButton
+ insertButton.apply( toolbar, button );
+ } else {
+ // Raw object from mw.toolbar.addButtons
+ insertButton( button );
+ }
+ }
+
+ // Clear queue
+ queue.length = 0;
+
+ // This causes further calls to addButton to go to insertion directly
+ // instead of to the queue.
+ // It is important that this is after the one and only loop through
+ // the queue
+ isReady = true;
+
+ // Apply to dynamically created textboxes as well as normal ones
+ $( document ).on( 'focus', 'textarea, input:text', function () {
+ $currentFocused = $( this );
+ } );
+ } );
+
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/mediawiki.action.edit.toolbar.less b/resources/src/mediawiki.toolbar/toolbar.less
index d65b2842..d65b2842 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.toolbar/mediawiki.action.edit.toolbar.less
+++ b/resources/src/mediawiki.toolbar/toolbar.less
diff --git a/resources/src/mediawiki.ui/components/anchors.less b/resources/src/mediawiki.ui/components/anchors.less
index e1b258dd..f0fb7b95 100644
--- a/resources/src/mediawiki.ui/components/anchors.less
+++ b/resources/src/mediawiki.ui/components/anchors.less
@@ -3,13 +3,8 @@
@import "mediawiki.ui/mixins";
// Helpers
-.mw-ui-anchor( @mainColor ) {
- // Make all context classes take the main color in IE6
- .select-ie6-only& {
- &:link, &:visited, &:hover, &:focus, &:active {
- color: @mainColor;
- }
- }
+.mixin-mw-ui-anchor-styles( @mainColor ) {
+ color: @mainColor;
// Hover state
&:hover {
@@ -21,57 +16,65 @@
outline: none; // outline fix
}
- color: @mainColor;
-
// Quiet mode is gray at first
&.mw-ui-quiet {
- .mw-ui-anchor-quiet( @mainColor );
+ .mixin-mw-ui-anchor-styles-quiet( @mainColor );
}
}
-.mw-ui-anchor-quiet( @mainColor ) {
- color: @colorTextLight;
- text-decoration: none;
+/*
+Anchors
- &:hover {
- color: @mainColor;
- }
- &:focus, &:active {
- color: darken( @mainColor, @colorDarkenPercentage );
- }
-}
+The anchor base type can be applied to A elements when a basic context styling needs to be given to a link, without
+having to assign it as a button type. mw-ui-anchor only changes the text color, and should not be used in combination
+with other base classes, such as mw-ui-button.
-/*
-Text & Anchors
+Markup:
+<a href="#" class="mw-ui-anchor mw-ui-progressive">Progressive</a>
+<a href="#" class="mw-ui-anchor mw-ui-constructive">Constructive</a>
+<a href="#" class="mw-ui-anchor mw-ui-destructive">Destructive</a>
-Allows you to give text a context as to the type of action it is indicating.
+.mw-ui-quiet - Quiet until interaction.
-Styleguide 6.
+Styleguide 6.2.
*/
+// Setup compound anchor selectors (such as .mw-ui-anchor.mw-ui-progressive)
+.mw-ui-anchor {
+ &.mw-ui-progressive {
+ .mixin-mw-ui-anchor-styles( @colorProgressive );
+ }
+
+ &.mw-ui-constructive {
+ .mixin-mw-ui-anchor-styles( @colorConstructive );
+ }
+
+ &.mw-ui-destructive {
+ .mixin-mw-ui-anchor-styles( @colorDestructive );
+ }
+}
+
/*
-Guidelines
+Quiet anchors
-This context should only applied on elements without special behavior (DIV, SPAN, etc.), including A elements. These classes cannot be applied for styling purposes on other elements (such as form elements), except when used in combination with .mw-ui-button to alter a button context.
+Use quiet anchors when they are less important and alongside other progressive/destructive/progressive
+anchors. Use of quiet anchors is not recommended on mobile/tablet due to lack of hover state.
Markup:
-<a href=# class="mw-ui-progressive {$modifiers}">Progressive</a>
-<a href=# class="mw-ui-constructive {$modifiers}">Constructive</a>
-<a href=# class="mw-ui-destructive {$modifiers}">Destructive</a>
+<a href="#" class="mw-ui-anchor mw-ui-progressive mw-ui-quiet">Progressive</a>
+<a href="#" class="mw-ui-anchor mw-ui-constructive mw-ui-quiet">Constructive</a>
+<a href="#" class="mw-ui-anchor mw-ui-destructive mw-ui-quiet">Destructive</a>
-.mw-ui-quiet - Quiet until interaction.
-
-Styleguide 6.1.
+Styleguide 6.2.1.
*/
-.mw-ui-progressive {
- .mw-ui-anchor( @colorProgressive );
-}
-.mw-ui-constructive {
- .mw-ui-anchor( @colorConstructive );
-}
-.mw-ui-destructive {
- .mw-ui-anchor( @colorDestructive );
-}
-.mw-ui-quiet {
- .mw-ui-anchor-quiet( @colorTextLight );
+.mixin-mw-ui-anchor-styles-quiet( @mainColor ) {
+ color: @colorTextLight;
+ text-decoration: none;
+
+ &:hover {
+ color: @mainColor;
+ }
+ &:focus, &:active {
+ color: darken( @mainColor, @colorDarkenPercentage );
+ }
}
diff --git a/resources/src/mediawiki.ui/components/buttons.less b/resources/src/mediawiki.ui/components/buttons.less
index f6a44fd4..f88f3ee6 100644
--- a/resources/src/mediawiki.ui/components/buttons.less
+++ b/resources/src/mediawiki.ui/components/buttons.less
@@ -17,6 +17,8 @@
// Neutral button styling
//
+// These are the main actions on the page/workflow. The page should have only one of progressive, constructive and desctructive buttons, the rest being quiet.
+//
// Markup:
// <div>
// <button class="mw-ui-button">.mw-ui-button</button>
@@ -47,7 +49,7 @@
// Container styling
.button-colors(#FFF);
border-radius: @borderRadius;
- min-width: 80px;
+ min-width: 4em;
// Ensure that buttons and inputs are nicely aligned when they have differing heights
vertical-align: middle;
@@ -165,8 +167,7 @@
// Destructive buttons
//
- // Use destructive buttons for actions which result in the destruction of data.
- // e.g. deleting a page.
+ // Use destructive buttons for actions that remove or limit, such as deleting a page or blocking a user.
// This should not be used for cancel buttons.
//
// Markup:
@@ -188,7 +189,8 @@
// Quiet buttons
//
- // Use quiet buttons when they are less important and alongisde other progressive/destructive/progressive buttons.
+ // Use quiet buttons when they are less important and alongside other constructive, progressive or destructive buttons. It should be used for an action that exits the user from the current view/workflow.
+ // Its use is not recommended on mobile/tablet due to lack of hover state.
//
// Markup:
// <div>
@@ -257,6 +259,7 @@ a.mw-ui-button {
//
// Styleguide 2.2.
.mw-ui-button-group > * {
+ min-width: 48px;
border-radius: 0;
float: left;
diff --git a/resources/src/mediawiki.ui/components/checkbox.less b/resources/src/mediawiki.ui/components/checkbox.less
index e39646bc..4829f5f6 100644
--- a/resources/src/mediawiki.ui/components/checkbox.less
+++ b/resources/src/mediawiki.ui/components/checkbox.less
@@ -11,27 +11,42 @@
//
// Markup:
// <div class="mw-ui-checkbox">
-// <input type="checkbox" id="kss-example-5"><label for="kss-example-5">Standard checkbox</label>
+// <input type="checkbox" id="kss-example-3">
+// <label for="kss-example-3">Standard checkbox</label>
// </div>
// <div class="mw-ui-checkbox">
-// <input type="checkbox" id="kss-example-5-2" disabled><label for="kss-example-5-2">Disabled checkbox</label>
+// <input type="checkbox" id="kss-example-3-checked" checked>
+// <label for="kss-example-3-checked">Standard checked checkbox</label>
+// </div>
+// <div class="mw-ui-checkbox">
+// <input type="checkbox" id="kss-example-3-disabled" disabled>
+// <label for="kss-example-3-disabled">Disabled checkbox</label>
+// </div>
+// <div class="mw-ui-checkbox">
+// <input type="checkbox" id="kss-example-3-disabled-checked" disabled checked>
+// <label for="kss-example-3-disabled-checked">Disabled checked checkbox</label>
// </div>
//
-// Styleguide 5.
+// Styleguide 3.
.mw-ui-checkbox {
display: inline-block;
vertical-align: middle;
}
-@checkboxSize: 24px;
+@checkboxSize: 2em;
// We use the not selector to cancel out styling on IE 8 and below
-.mw-ui-checkbox:not(#noop) {
+// We also disable this styling on javascript disabled devices. This fixes the issue with
+// Opera Mini where checking/unchecking doesn't apply styling but potentially leaves other
+// more capable browsers with unstyled checkboxes.
+.client-js .mw-ui-checkbox:not(#noop) {
// Position relatively so we can make use of absolute pseudo elements
position: relative;
- line-height: @checkboxSize;
+ display: table;
* {
+ // reset font sizes (see bug 72727)
+ font: inherit;
vertical-align: middle;
}
@@ -42,59 +57,70 @@
// ensure the invisible checkbox takes up the required width
width: @checkboxSize;
height: @checkboxSize;
+ // This is needed for Firefox mobile (See bug 71750 to workaround default Firefox stylesheet)
+ max-width: none;
+ margin: 0;
+ margin-right: 0.4em;
+ display: table-cell;
- // the pseudo before element of the label after the checkbox now looks like a checkbox
& + label {
- cursor: pointer;
+ display: table-cell;
+ }
- &::before {
- content: '';
- position: absolute;
- left: 0;
- display: inline-block;
- border-radius: @borderRadius;
- margin-right: 18px;
- width: @checkboxSize;
- height: @checkboxSize;
- background-color: #fff;
- border: 1px solid grey;
- }
+ // the pseudo before element of the label after the checkbox now looks like a checkbox
+ & + label::before {
+ .transition( 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275) );
+ content: '';
+ cursor: pointer;
+ .box-sizing(border-box);
+ position: absolute;
+ left: 0;
+ border-radius: @borderRadius;
+ width: @checkboxSize;
+ height: @checkboxSize;
+ line-height: @checkboxSize;
+ background-color: #fff;
+ border: 1px solid @colorGray7;
+ // align the checkbox to middle of the text
+ top: 50%;
+ margin-top: -1em;
+ .background-image-svg('images/checked.svg', 'images/checked.png');
+ .background-size( @checkboxSize - 0.2em, @checkboxSize - 0.2em );
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-origin: border-box;
+ background-size: 0 0;
}
// when the input is checked, style the label pseudo before element that followed as a checked checkbox
- &:checked {
- + label {
- &::before {
- .background-image-svg('images/checked.svg', 'images/checked.png');
- background-repeat: no-repeat;
- background-position: center top;
- }
- }
+ &:checked + label::before {
+ background-size: 100% 100%;
+ }
+
+ &:active + label::before {
+ background-color: @colorGray13;
+ border-color: @colorGray13;
}
- @focusBottomBorderSize: 3px;
- &:active,
- &:focus {
- + label {
- &::after {
- content: '';
- position: absolute;
- width: @checkboxSize;
- height: @checkboxSize - @focusBottomBorderSize + 1; // offset by bottom border
- // offset from the checkbox by 1px to account for left border
- left: 1px;
- border-bottom: solid @focusBottomBorderSize lightgrey;
- }
- }
+ &:focus + label::before {
+ border-width: 2px;
}
- // disabled checked boxes have a gray background
- &:disabled + label {
+ &:focus:hover + label::before,
+ &:hover + label::before {
+ border-bottom-width: 3px;
+ }
+
+ // disabled checkboxes have a gray background
+ &:disabled + label::before {
cursor: default;
+ background-color: @colorGray14;
+ border-color: @colorGray14;
+ }
- &::before {
- background-color: lightgrey;
- }
+ // disabled and checked checkboxes have a white circle
+ &:disabled:checked + label::before {
+ .background-image-svg('images/checked_disabled.svg', 'images/checked_disabled.png');
}
}
}
diff --git a/resources/src/mediawiki.ui/components/forms.less b/resources/src/mediawiki.ui/components/forms.less
index 592a3098..dc49e202 100644
--- a/resources/src/mediawiki.ui/components/forms.less
+++ b/resources/src/mediawiki.ui/components/forms.less
@@ -15,7 +15,7 @@
// Forms
//
-// Styleguide 3.
+// Styleguide 5.
// VForm
//
@@ -34,7 +34,7 @@
// </div>
// </form>
//
-// Styleguide 3.1.
+// Styleguide 5.1.
.mw-ui-vform {
.box-sizing(border-box);
@@ -102,7 +102,7 @@
// </div>
// </form>
//
- // Styleguide 3.2.
+ // Styleguide 5.2.
.error,
.errorbox,
.warningbox,
@@ -153,14 +153,15 @@
// You generally don't need to use this class if <label> is within an Agora
// form container such as mw-ui-vform
.mw-ui-label {
- .agora-label-styling(); // mixins/forms.less
+ .agora-label-styling();
}
// Nesting an input inside a label with this class
// improves alignment, e.g.
-// <label class="mw-ui-radio-label">
-// <input type="radio">The label text
-// </label>
+//
+// <label class="mw-ui-radio-label">
+// <input type="radio">The label text
+// </label>
.mw-ui-radio-label {
.agora-inline-label-styling();
}
diff --git a/resources/src/mediawiki.ui/components/icons.less b/resources/src/mediawiki.ui/components/icons.less
new file mode 100644
index 00000000..ad951b08
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/icons.less
@@ -0,0 +1,107 @@
+@import "mediawiki.mixins";
+
+// Variables
+@iconSize: 1.4em;
+@gutterWidth: 1em;
+
+// Mixins
+.mixin-mw-ui-icon-bgimage(@iconSvg, @iconPng) {
+ &.mw-ui-icon {
+ &:after,
+ &:before {
+ .background-image-svg(@iconSvg, @iconPng);
+ }
+ }
+}
+
+// Icons
+//
+// To use icons you must be using a browser that supports pseudo elements.
+// This includes support for IE8.
+// http://caniuse.com/#feat=css-gencontent
+//
+// For elements that are intended to have both an icon and text, browsers that
+// do not support pseudo-selectors will degrade to text-only.
+//
+// However, icon-only elements do not yet degrade to text-only elements in these
+// browsers.
+//
+// Styleguide 6.
+
+.mw-ui-icon {
+ position: relative;
+ min-height: @iconSize;
+ min-width: @iconSize;
+
+ // Standalone icons
+ //
+ // Markup:
+ // <div class="mw-ui-icon mw-ui-icon-element mw-ui-icon-ok">OK</div><br/>
+ // <div class="mw-ui-icon mw-ui-icon-element mw-ui-icon-ok mw-ui-button mw-ui-progressive">OK</div><br/>
+ // <button class="mw-ui-icon mw-ui-icon-ok mw-ui-icon-element mw-ui-button mw-ui-quiet" title="">Close</button>
+ //
+ // Styleguide 6.1.1.
+ &.mw-ui-icon-element {
+ @width: @iconSize + ( 2 * @gutterWidth );
+
+ text-indent: -999px;
+ overflow: hidden;
+ width: @width;
+ min-width: @width;
+ max-width: @width;
+ &:before {
+ left: 0;
+ right: 0;
+ position: absolute;
+ margin: 0 @gutterWidth;
+ }
+ }
+
+ &.mw-ui-icon-after:after,
+ &.mw-ui-icon-before:before,
+ &.mw-ui-icon-element:before {
+ background-position: 50% 50%;
+ float: left;
+ display: block;
+ background-repeat: no-repeat;
+ background-size: 100% auto;
+ min-height: @iconSize;
+ content: '';
+ }
+
+
+ // Icons with text
+ //
+ // Markup:
+ // <div class="mw-ui-icon mw-ui-icon-before mw-ui-icon-ok">OK</div>
+ // <div class="mw-ui-icon mw-ui-icon-before mw-ui-icon-ok mw-ui-progressive mw-ui-button">OK</div>
+ //
+ // Styleguide 6.1.2
+ &.mw-ui-icon-before {
+ &:before {
+ position: relative;
+ width: @iconSize;
+ margin-right: @gutterWidth;
+ }
+ }
+
+ // Icons with text before
+ //
+ // Markup:
+ // <div class="mw-ui-icon mw-ui-icon-after mw-ui-icon-ok mw-ui-progressive mw-ui-button">OK</div>
+ //
+ // Styleguide 6.1.3
+ &.mw-ui-icon-after {
+ &:after {
+ position: relative;
+ float: right;
+ width: @iconSize;
+ margin-left: @gutterWidth;
+ }
+ }
+}
+
+// Icons
+.mw-ui-icon-ok {
+ .mixin-mw-ui-icon-bgimage('images/ok.svg', 'images/ok.png');
+}
diff --git a/resources/src/mediawiki.ui/components/images/checked.svg b/resources/src/mediawiki.ui/components/images/checked.svg
index aea69db4..aca2b2b0 100644
--- a/resources/src/mediawiki.ui/components/images/checked.svg
+++ b/resources/src/mediawiki.ui/components/images/checked.svg
@@ -1 +1 @@
-<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M4 12l5 5 11-12" stroke="#00B78C" stroke-width="3" fill="none"/></svg> \ No newline at end of file
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M4 12l5 5L20 5" stroke="#00B78C" stroke-width="3" fill="none"/></svg>
diff --git a/resources/src/mediawiki.ui/components/images/checked_disabled.png b/resources/src/mediawiki.ui/components/images/checked_disabled.png
new file mode 100644
index 00000000..523b880f
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/images/checked_disabled.png
Binary files differ
diff --git a/resources/src/mediawiki.ui/components/images/checked_disabled.svg b/resources/src/mediawiki.ui/components/images/checked_disabled.svg
new file mode 100644
index 00000000..ba4010ee
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/images/checked_disabled.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><path d="M4 12l5 5L20 5" stroke="#fff" stroke-width="3" fill="none"/></svg>
diff --git a/resources/src/mediawiki.ui/components/images/ok.png b/resources/src/mediawiki.ui/components/images/ok.png
new file mode 100644
index 00000000..1ea6aa2d
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/images/ok.png
Binary files differ
diff --git a/resources/src/mediawiki.ui/components/images/ok.svg b/resources/src/mediawiki.ui/components/images/ok.svg
new file mode 100644
index 00000000..a3d3058a
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/images/ok.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="22" height="22"><path d="M18.125 1.813l-10.5 10.75-3.844-3.75L0 12.719l7.72 7.452L22 5.625z" fill="#f0f0f0"/></svg>
diff --git a/resources/src/mediawiki.ui/components/images/radio_checked.png b/resources/src/mediawiki.ui/components/images/radio_checked.png
new file mode 100644
index 00000000..d5735164
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/images/radio_checked.png
Binary files differ
diff --git a/resources/src/mediawiki.ui/components/images/radio_checked.svg b/resources/src/mediawiki.ui/components/images/radio_checked.svg
new file mode 100644
index 00000000..c8b9b625
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/images/radio_checked.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><circle fill="#00AF89" cx="12" cy="12" r="6"/></svg>
diff --git a/resources/src/mediawiki.ui/components/images/radio_disabled.png b/resources/src/mediawiki.ui/components/images/radio_disabled.png
new file mode 100644
index 00000000..945b3dde
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/images/radio_disabled.png
Binary files differ
diff --git a/resources/src/mediawiki.ui/components/images/radio_disabled.svg b/resources/src/mediawiki.ui/components/images/radio_disabled.svg
new file mode 100644
index 00000000..ec8ffe3e
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/images/radio_disabled.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8"?><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><circle fill="#fff" cx="12" cy="12" r="6"/></svg>
diff --git a/resources/src/mediawiki.ui/components/inputs.less b/resources/src/mediawiki.ui/components/inputs.less
index 1da42a45..2f761312 100644
--- a/resources/src/mediawiki.ui/components/inputs.less
+++ b/resources/src/mediawiki.ui/components/inputs.less
@@ -9,7 +9,7 @@
font-style: italic;
font-weight: normal;
}
-// Inputs
+// Text inputs
//
// Apply the mw-ui-input class to input and textarea fields.
//
@@ -32,16 +32,14 @@
border: 1px solid @colorFieldBorder;
.box-sizing(border-box);
width: 100%;
- padding: .4em .3em .2em .6em;
+ padding: .3em .3em .3em .6em;
display: block;
vertical-align: middle;
border-radius: @borderRadius;
- // Override user agent stylesheet properties. Instead use parent element.
- color: inherit;
font-family: inherit;
font-size: inherit;
line-height: inherit;
- .transition(~"border linear .2s, box-shadow linear .2s");
+ .transition(~"border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 0.2s cubic-bezier(0.39, 0.575, 0.565, 1)");
// Placeholder text styling must be set individually for each browser @winter
&::-webkit-input-placeholder { // webkit
@@ -66,11 +64,17 @@
}
&:focus {
- box-shadow: inset .45em 0 0 @colorProgressive;
- border-color: @colorGrayDark;
+ box-shadow: inset 0 0 0 2px @colorProgressive;
+ // Color being used to match inset shadow, not semantic reasons
+ border-color: @colorProgressive;
// Remove focus glow on input[type="search"]
outline: 0;
}
+
+ &:disabled {
+ border-color: @colorGray14;
+ color: @colorGray12;
+ }
}
textarea.mw-ui-input {
@@ -83,7 +87,7 @@ textarea.mw-ui-input {
//
// Markup:
// <input class="mw-ui-input mw-ui-input-inline">
-// <button class="mw-ui-button mw-ui-constructive">go</button>
+// <button class="mw-ui-button mw-ui-constructive">Submit</button>
//
// Styleguide 1.2.
input[type="number"],
diff --git a/resources/src/mediawiki.ui/components/radio.less b/resources/src/mediawiki.ui/components/radio.less
new file mode 100644
index 00000000..1928699b
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/radio.less
@@ -0,0 +1,116 @@
+@import "mediawiki.mixins";
+@import "mediawiki.ui/variables";
+
+// Radio
+//
+// Styling radios in a way that works cross browser is a tricky problem to solve.
+// In MediaWiki UI put a radio and label inside a mw-ui-radio div.
+// This renders in all browsers except IE6-8 which do not support the :checked selector;
+// these are kept backwards-compatible using the :not(#noop) selector.
+// You should give the radio and label matching "id" and "for" attributes, respectively.
+//
+// Markup:
+// <div class="mw-ui-radio">
+// <input type="radio" id="kss-example-4" name="kss-example-4">
+// <label for="kss-example-4">Standard radio</label>
+// </div>
+// <div class="mw-ui-radio">
+// <input type="radio" id="kss-example-4-checked" name="kss-example-4" checked>
+// <label for="kss-example-4-checked">Standard checked radio</label>
+// </div>
+// <div class="mw-ui-radio">
+// <input type="radio" id="kss-example-4-disabled" name="kss-example-4-disabled" disabled>
+// <label for="kss-example-4-disabled">Disabled radio</label>
+// </div>
+// <div class="mw-ui-radio">
+// <input type="radio" id="kss-example-4-disabled-checked" name="kss-example-4-disabled" disabled checked>
+// <label for="kss-example-4-disabled-checked">Disabled checked radio</label>
+// </div>
+//
+// Styleguide 4.
+.mw-ui-radio {
+ display: inline-block;
+ vertical-align: middle;
+}
+
+@radioSize: 2em;
+
+// We use the not selector to cancel out styling on IE 8 and below.
+// We also disable this styling on javascript disabled devices. This fixes the issue with
+// Opera Mini where checking/unchecking doesn't apply styling but potentially leaves other
+// more capable browsers with unstyled radio buttons.
+.client-js .mw-ui-radio:not(#noop) {
+ // Position relatively so we can make use of absolute pseudo elements
+ position: relative;
+ line-height: @radioSize;
+
+ * {
+ // reset font sizes (see bug 72727)
+ font: inherit;
+ vertical-align: middle;
+ }
+
+ input[type="radio"] {
+ // we hide the input element as instead we will style the label that follows
+ // we use opacity so that VoiceOver software can still identify it
+ opacity: 0;
+ // ensure the invisible radio takes up the required width
+ width: @radioSize;
+ height: @radioSize;
+ // This is needed for Firefox mobile (See bug 71750 to workaround default Firefox stylesheet)
+ max-width: none;
+ margin-right: 0.4em;
+
+ // the pseudo before element of the label after the radio now looks like a radio
+ & + label::before {
+ .transition( 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275) );
+ content: '';
+ cursor: pointer;
+ .box-sizing(border-box);
+ position: absolute;
+ left: 0;
+ border-radius: 100%;
+ width: @radioSize;
+ height: @radioSize;
+ background-color: #fff;
+ border: 1px solid @colorGray7;
+ .background-image-svg('images/radio_checked.svg', 'images/radio_checked.png');
+ .background-size( @radioSize, @radioSize );
+ background-repeat: no-repeat;
+ background-position: center center;
+ background-origin: border-box;
+ background-size: 0 0;
+ }
+
+ // when the input is checked, style the label pseudo before element that followed as a checked radio
+ &:checked + label::before {
+ background-size: 100% 100%;
+ }
+
+ &:active + label::before {
+ background-color: @colorGray13;
+ border-color: @colorGray13;
+ }
+
+ &:focus + label::before {
+ border-width: 2px;
+ }
+
+ &:focus:hover + label::before,
+ &:hover + label::before {
+ border-bottom-width: 3px;
+ }
+
+ // disabled radios have a gray background
+ &:disabled + label::before {
+ cursor: default;
+ background-color: @colorGray14;
+ border-color: @colorGray14;
+ }
+
+ // disabled and checked radios have a white circle
+ &:disabled:checked + label::before {
+ .background-image-svg('images/radio_disabled.svg', 'images/radio_disabled.png');
+ }
+ }
+}
diff --git a/resources/src/mediawiki.ui/components/text.less b/resources/src/mediawiki.ui/components/text.less
new file mode 100644
index 00000000..500d42c4
--- /dev/null
+++ b/resources/src/mediawiki.ui/components/text.less
@@ -0,0 +1,40 @@
+@import "mediawiki.mixins";
+@import "mediawiki.ui/variables";
+@import "mediawiki.ui/mixins";
+
+/*
+Text & Anchors
+
+Allows you to give text a context as to the type of action it is indicating.
+
+Styleguide 6.
+*/
+
+/*
+Text
+
+Context classes may be used on elements with only plain-text content with the mw-ui-text base. When the context classes
+are used on interactive and block-level elements, the appropriate alternative base type classes should also be used. For
+example, mw-ui-anchor with A, or mw-ui-button with buttons.
+
+Markup:
+<span class="mw-ui-text mw-ui-progressive">Progressive</span>
+<span class="mw-ui-text mw-ui-constructive">Constructive</span>
+<span class="mw-ui-text mw-ui-destructive">Destructive</span>
+
+Styleguide 6.1.
+*/
+
+.mw-ui-text {
+ // The selector order is like this on purpose; IE6 ignores the second selector,
+ // so we don't want to accidentally apply this color on all mw-ui-CONTEXT classes
+ .mw-ui-progressive& {
+ color: @colorProgressive;
+ }
+ .mw-ui-constructive& {
+ color: @colorConstructive;
+ }
+ .mw-ui-destructive& {
+ color: @colorDestructive;
+ }
+} \ No newline at end of file
diff --git a/resources/src/mediawiki/images/help.png b/resources/src/mediawiki/images/help.png
new file mode 100644
index 00000000..99105822
--- /dev/null
+++ b/resources/src/mediawiki/images/help.png
Binary files differ
diff --git a/resources/src/mediawiki/images/help.svg b/resources/src/mediawiki/images/help.svg
new file mode 100644
index 00000000..3662cb58
--- /dev/null
+++ b/resources/src/mediawiki/images/help.svg
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="utf-8"?><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><g><path d="M12.001 2.085c-5.478 0-9.916 4.438-9.916 9.916 0 5.476 4.438 9.914 9.916 9.914 5.476 0 9.914-4.438 9.914-9.914 0-5.478-4.438-9.916-9.914-9.916zm.001 18c-4.465 0-8.084-3.619-8.084-8.083 0-4.465 3.619-8.084 8.084-8.084 4.464 0 8.083 3.619 8.083 8.084 0 4.464-3.619 8.083-8.083 8.083z"/><g><path d="M11.766 6.688c-2.5 0-3.219 2.188-3.219 2.188l1.411.854s.298-.791.901-1.229c.516-.375 1.625-.625 2.219.125.701.885-.17 1.587-1.078 2.719-.953 1.186-1 3.655-1 3.655h1.969s.135-2.318 1.041-3.381c.603-.707 1.443-1.338 1.443-2.494s-1.187-2.437-3.687-2.437z"/><path d="M11 16h2v2h-2z"/></g></g></svg>
diff --git a/resources/src/mediawiki/images/pager-arrow-disabled-fastforward-ltr.svg b/resources/src/mediawiki/images/pager-arrow-disabled-fastforward-ltr.svg
new file mode 100644
index 00000000..b34fb382
--- /dev/null
+++ b/resources/src/mediawiki/images/pager-arrow-disabled-fastforward-ltr.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="30"
+ height="30"
+ id="svg2">
+ <defs
+ id="defs4" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="matrix(0.41333074,0,0,0.41333074,-183.39876,-197.95599)"
+ id="layer1">
+ <g
+ transform="translate(455.60433,484.94177)"
+ id="g3163">
+ <path
+ d="M 0,0.03543307 0,60.519684 43.192915,30.259842 z"
+ id="path3165"
+ style="fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ <path
+ d="m 43.157481,0.03543307 5.633859,0 0,60.48425093 -5.633859,0 z"
+ id="path3167"
+ style="fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none" />
+ </g>
+ </g>
+</svg>
diff --git a/resources/src/mediawiki/images/pager-arrow-disabled-fastforward-rtl.svg b/resources/src/mediawiki/images/pager-arrow-disabled-fastforward-rtl.svg
new file mode 100644
index 00000000..529e8d0f
--- /dev/null
+++ b/resources/src/mediawiki/images/pager-arrow-disabled-fastforward-rtl.svg
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="30"
+ height="30"
+ id="svg2">
+ <defs
+ id="defs4" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="matrix(0.4132798,0,0,0.4132798,-87.72955,-233.35372)"
+ id="layer1">
+ <path
+ d="m 272.96237,570.69005 0,60.4894 -43.19393,-30.2447 z"
+ id="path3023-7"
+ style="fill:#cccccc;fill-opacity:1;stroke:none" />
+ <rect
+ width="5.6406202"
+ height="60.489399"
+ x="-229.82111"
+ y="570.68774"
+ transform="scale(-1,1)"
+ id="rect3799-9"
+ style="color:#000000;fill:#cccccc;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:20;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ </g>
+</svg>
diff --git a/resources/src/mediawiki/images/pager-arrow-disabled-forward-ltr.svg b/resources/src/mediawiki/images/pager-arrow-disabled-forward-ltr.svg
new file mode 100644
index 00000000..9fbcf20e
--- /dev/null
+++ b/resources/src/mediawiki/images/pager-arrow-disabled-forward-ltr.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="30"
+ height="30"
+ id="svg2">
+ <defs
+ id="defs4" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="matrix(0.41329555,0,0,0.41329555,-111.35036,-135.3531)"
+ id="layer1">
+ <path
+ d="m 284.11732,333.54605 0,60.4894 43.19395,-30.2447 z"
+ id="path3023-7-2"
+ style="fill:#cccccc;fill-opacity:1;stroke:none" />
+ </g>
+</svg>
diff --git a/resources/src/mediawiki/images/pager-arrow-disabled-forward-rtl.svg b/resources/src/mediawiki/images/pager-arrow-disabled-forward-rtl.svg
new file mode 100644
index 00000000..3130f109
--- /dev/null
+++ b/resources/src/mediawiki/images/pager-arrow-disabled-forward-rtl.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="30"
+ height="30"
+ id="svg2">
+ <defs
+ id="defs4" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="matrix(0.41329555,0,0,0.41329555,-139.69062,-163.69336)"
+ id="layer1">
+ <path
+ d="m 395.88269,402.11748 0,60.4894 -43.19395,-30.2447 z"
+ id="path3023-7-2-8"
+ style="fill:#cccccc;fill-opacity:1;stroke:none" />
+ </g>
+</svg>
diff --git a/resources/src/mediawiki/images/pager-arrow-fastforward-ltr.svg b/resources/src/mediawiki/images/pager-arrow-fastforward-ltr.svg
new file mode 100644
index 00000000..57df4c0d
--- /dev/null
+++ b/resources/src/mediawiki/images/pager-arrow-fastforward-ltr.svg
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="30"
+ height="30"
+ id="svg2">
+ <defs
+ id="defs4" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="matrix(0.41327999,0,0,0.41327999,-98.356798,-226.26904)"
+ id="layer1">
+ <path
+ d="m 249.89477,553.5472 0,60.4894 43.19391,-30.2447 z"
+ id="path3023"
+ style="fill:#0000aa;fill-opacity:1;stroke:none" />
+ <rect
+ width="5.6406202"
+ height="60.489399"
+ x="293.03604"
+ y="553.54492"
+ id="rect3799"
+ style="color:#000000;fill:#0000aa;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:20;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ </g>
+</svg>
diff --git a/resources/src/mediawiki/images/pager-arrow-fastforward-rtl.svg b/resources/src/mediawiki/images/pager-arrow-fastforward-rtl.svg
new file mode 100644
index 00000000..dbb473bb
--- /dev/null
+++ b/resources/src/mediawiki/images/pager-arrow-fastforward-rtl.svg
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.1"
+ width="30"
+ height="30"
+ id="svg2"
+ inkscape:version="0.48.4 r9939"
+ sodipodi:docname="pager-arrow-fastforward-rtl.svg">
+ <sodipodi:namedview
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1"
+ objecttolerance="10"
+ gridtolerance="10"
+ guidetolerance="10"
+ inkscape:pageopacity="0"
+ inkscape:pageshadow="2"
+ inkscape:window-width="1366"
+ inkscape:window-height="692"
+ id="namedview8"
+ showgrid="false"
+ inkscape:zoom="17.4"
+ inkscape:cx="7.0114943"
+ inkscape:cy="15"
+ inkscape:window-x="0"
+ inkscape:window-y="24"
+ inkscape:window-maximized="1"
+ inkscape:current-layer="svg2" />
+ <defs
+ id="defs4" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="matrix(0.07055556,0,0,0.07055556,-9.1581596,-2.7587241)"
+ id="layer1">
+ <path
+ d="m 485.26916,74.546776 0,354.317014 -253.00859,-177.15851 z"
+ id="path3023-2"
+ style="fill:#0000aa;fill-opacity:1;stroke:none"
+ inkscape:connector-curvature="0" />
+ <rect
+ width="33.039963"
+ height="354.31699"
+ x="-232.56898"
+ y="74.533081"
+ transform="scale(-1,1)"
+ id="rect3799-6"
+ style="color:#000000;fill:#0000aa;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:20;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate" />
+ </g>
+</svg>
diff --git a/resources/src/mediawiki/images/pager-arrow-forward-ltr.svg b/resources/src/mediawiki/images/pager-arrow-forward-ltr.svg
new file mode 100644
index 00000000..1ebf9c15
--- /dev/null
+++ b/resources/src/mediawiki/images/pager-arrow-forward-ltr.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="30"
+ height="30"
+ id="svg2">
+ <defs
+ id="defs4" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="matrix(0.41329555,0,0,0.41329555,-162.12666,-110.55537)"
+ id="layer1">
+ <path
+ d="m 406.97447,273.54605 0,60.4894 43.19391,-30.2447 z"
+ id="path3023-3-9"
+ style="fill:#0000aa;fill-opacity:1;stroke:none" />
+ </g>
+</svg>
diff --git a/resources/src/mediawiki/images/pager-arrow-forward-rtl.svg b/resources/src/mediawiki/images/pager-arrow-forward-rtl.svg
new file mode 100644
index 00000000..b494409a
--- /dev/null
+++ b/resources/src/mediawiki/images/pager-arrow-forward-rtl.svg
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ version="1.1"
+ width="30"
+ height="30"
+ id="svg2">
+ <defs
+ id="defs4" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ transform="matrix(0.41329555,0,0,0.41329555,-78.28671,-153.06577)"
+ id="layer1">
+ <path
+ d="m 247.31124,376.4032 0,60.4894 -43.19391,-30.2447 z"
+ id="path3023-3"
+ style="fill:#0000aa;fill-opacity:1;stroke:none" />
+ </g>
+</svg>
diff --git a/resources/src/mediawiki/mediawiki.Title.js b/resources/src/mediawiki/mediawiki.Title.js
index 7ced42fe..3efb7eca 100644
--- a/resources/src/mediawiki/mediawiki.Title.js
+++ b/resources/src/mediawiki/mediawiki.Title.js
@@ -8,7 +8,7 @@
/**
* @class mw.Title
*
- * Parse titles into an object struture. Note that when using the constructor
+ * Parse titles into an object structure. Note that when using the constructor
* directly, passing invalid titles will result in an exception. Use #newFromText to use the
* logic directly and get null for invalid titles which is easier to work with.
*
@@ -119,7 +119,7 @@
rSplit = /^(.+?)_*:_*(.*)$/,
- // See Title.php#getTitleInvalidRegex
+ // See MediaWikiTitleCodec.php#getTitleInvalidRegex
rInvalid = new RegExp(
'[^' + mw.config.get( 'wgLegalTitleChars' ) + ']' +
// URL percent encoding sequences interfere with the ability
@@ -508,7 +508,7 @@
normalizeExtension = function ( extension ) {
// Remove only trailing space (that is removed by MW anyway)
- extension = extension.toLowerCase().replace(/\s*$/, '');
+ extension = extension.toLowerCase().replace( /\s*$/, '' );
return extension;
};
@@ -731,7 +731,10 @@
set: function ( titles, state ) {
titles = $.isArray( titles ) ? titles : [titles];
state = state === undefined ? true : !!state;
- var pages = this.pages, i, len = titles.length;
+ var i,
+ pages = this.pages,
+ len = titles.length;
+
for ( i = 0; i < len; i++ ) {
pages[ titles[i] ] = state;
}
diff --git a/resources/src/mediawiki/mediawiki.Uri.js b/resources/src/mediawiki/mediawiki.Uri.js
index 55663128..abfb2790 100644
--- a/resources/src/mediawiki/mediawiki.Uri.js
+++ b/resources/src/mediawiki/mediawiki.Uri.js
@@ -127,15 +127,29 @@
*/
/**
- * A factory method to create a variation of mw.Uri with a different default location (for
- * relative URLs, including protocol-relative URLs). Used so the library is still testable &
- * purely functional.
+ * A factory method to create a Uri class with a default location to resolve relative URLs
+ * against (including protocol-relative URLs).
*
* @method
+ * @param {string|Function} documentLocation A full url, or function returning one.
+ * If passed a function, the return value may change over time and this will be honoured. (T74334)
* @member mw
*/
mw.UriRelative = function ( documentLocation ) {
- var defaultUri;
+ var getDefaultUri = ( function () {
+ // Cache
+ var href, uri;
+
+ return function () {
+ var hrefCur = typeof documentLocation === 'string' ? documentLocation : documentLocation();
+ if ( href === hrefCur ) {
+ return uri;
+ }
+ href = hrefCur;
+ uri = new Uri( href );
+ return uri;
+ };
+ }() );
/**
* @class mw.Uri
@@ -147,8 +161,8 @@
* @param {Object|string} [uri] URI string, or an Object with appropriate properties (especially
* another URI object to clone). Object must have non-blank `protocol`, `host`, and `path`
* properties. If omitted (or set to `undefined`, `null` or empty string), then an object
- * will be created for the default `uri` of this constructor (`document.location` for
- * mw.Uri, other values for other instances -- see mw.UriRelative for details).
+ * will be created for the default `uri` of this constructor (`location.href` for mw.Uri,
+ * other values for other instances -- see mw.UriRelative for details).
* @param {Object|boolean} [options] Object with options, or (backwards compatibility) a boolean
* for strictMode
* @param {boolean} [options.strictMode=false] Trigger strict mode parsing of the url.
@@ -156,6 +170,9 @@
* override each other (`true`) or automagically convert them to an array (`false`).
*/
function Uri( uri, options ) {
+ var prop,
+ defaultUri = getDefaultUri();
+
options = typeof options === 'object' ? options : { strictMode: !!options };
options = $.extend( {
strictMode: false,
@@ -167,7 +184,7 @@
this.parse( uri, options );
} else if ( typeof uri === 'object' ) {
// Copy data over from existing URI object
- for ( var prop in uri ) {
+ for ( prop in uri ) {
// Only copy direct properties, not inherited ones
if ( uri.hasOwnProperty( prop ) ) {
// Deep copy object properties
@@ -390,14 +407,12 @@
}
};
- defaultUri = new Uri( documentLocation );
-
return Uri;
};
- // If we are running in a browser, inject the current document location (for relative URLs).
- if ( document && document.location && document.location.href ) {
- mw.Uri = mw.UriRelative( document.location.href );
- }
+ // Default to the current browsing location (for relative URLs).
+ mw.Uri = mw.UriRelative( function () {
+ return location.href;
+ } );
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.apihelp.css b/resources/src/mediawiki/mediawiki.apihelp.css
new file mode 100644
index 00000000..d1272323
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.apihelp.css
@@ -0,0 +1,86 @@
+.apihelp-header {
+ clear: both;
+ margin-bottom: 0.1em;
+}
+
+div.apihelp-linktrail {
+ font-size: smaller;
+}
+
+.apihelp-block {
+ margin-top: 0.5em;
+}
+
+.apihelp-block-head {
+ font-weight: bold;
+}
+
+.apihelp-flags {
+ font-size: smaller;
+ float: right;
+ border: 1px solid black;
+ padding: 0.25em;
+ width: 20em;
+}
+
+.apihelp-deprecated, .apihelp-flag-deprecated,
+.apihelp-flag-internal strong {
+ font-weight: bold;
+ color: red;
+}
+
+.apihelp-empty {
+ color: #888;
+}
+
+.apihelp-help-urls ul {
+ list-style-image: none;
+ list-style-type: none;
+ margin-left: 0;
+}
+
+.apihelp-parameters dl,
+.apihelp-examples dl,
+.apihelp-permissions dl {
+ margin-left: 2em;
+}
+
+.apihelp-parameters dt {
+ float: left;
+ clear: left;
+ min-width: 10em;
+ white-space: nowrap;
+ line-height: 1.5em;
+}
+
+.apihelp-parameters dt:after {
+ content: ':\A0'
+}
+
+.apihelp-parameters dd {
+ margin: 0 0 0.5em 10em;
+ line-height: 1.5em;
+}
+
+.apihelp-parameters dd p:first-child {
+ margin-top: 0;
+}
+
+.apihelp-parameters dd.info {
+ margin-left: 12em;
+ text-indent: -2em;
+}
+
+.apihelp-examples dt {
+ font-weight: normal;
+}
+
+.api-main-links {
+ text-align: center;
+}
+.api-main-links ul:before {
+ content: '[';
+}
+.api-main-links ul:after {
+ content: ']';
+}
diff --git a/resources/src/mediawiki/mediawiki.apipretty.css b/resources/src/mediawiki/mediawiki.apipretty.css
new file mode 100644
index 00000000..fe5e634d
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.apipretty.css
@@ -0,0 +1,11 @@
+h1.firstHeading {
+ display: none;
+}
+
+.api-pretty-header {
+ font-size: small;
+}
+
+.api-pretty-content {
+ white-space: pre-wrap;
+}
diff --git a/resources/src/mediawiki/mediawiki.confirmCloseWindow.js b/resources/src/mediawiki/mediawiki.confirmCloseWindow.js
new file mode 100644
index 00000000..7fc5c424
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.confirmCloseWindow.js
@@ -0,0 +1,68 @@
+( function ( mw, $ ) {
+ /**
+ * @method confirmCloseWindow
+ * @member mw
+ *
+ * Prevent the closing of a window with a confirm message (the onbeforeunload event seems to
+ * work in most browsers.)
+ *
+ * This supersedes any previous onbeforeunload handler. If there was a handler before, it is
+ * restored when you execute the returned function.
+ *
+ * var allowCloseWindow = mw.confirmCloseWindow();
+ * // ... do stuff that can't be interrupted ...
+ * allowCloseWindow();
+ *
+ * @param {Object} [options]
+ * @param {string} [options.namespace] Namespace for the event registration
+ * @param {string} [options.message]
+ * @param {string} options.message.return The string message to show in the confirm dialog.
+ * @param {Function} [options.test]
+ * @param {boolean} [options.test.return=true] Whether to show the dialog to the user.
+ * @return {Function} Execute this when you want to allow the user to close the window
+ */
+ mw.confirmCloseWindow = function ( options ) {
+ var savedUnloadHandler,
+ mainEventName = 'beforeunload',
+ showEventName = 'pageshow';
+
+ options = $.extend( {
+ message: mw.message( 'mwe-prevent-close' ).text(),
+ test: function () { return true; }
+ }, options );
+
+ if ( options.namespace ) {
+ mainEventName += '.' + options.namespace;
+ showEventName += '.' + options.namespace;
+ }
+
+ $( window ).on( mainEventName, function () {
+ if ( options.test() ) {
+ // remove the handler while the alert is showing - otherwise breaks caching in Firefox (3?).
+ // but if they continue working on this page, immediately re-register this handler
+ savedUnloadHandler = window.onbeforeunload;
+ window.onbeforeunload = null;
+ setTimeout( function () {
+ window.onbeforeunload = savedUnloadHandler;
+ }, 1 );
+
+ // show an alert with this message
+ if ( $.isFunction( options.message ) ) {
+ return options.message();
+ } else {
+ return options.message;
+ }
+ }
+ } ).on( showEventName, function () {
+ // Re-add onbeforeunload handler
+ if ( !window.onbeforeunload && savedUnloadHandler ) {
+ window.onbeforeunload = savedUnloadHandler;
+ }
+ } );
+
+ // return the function they can use to stop this
+ return function () {
+ $( window ).off( mainEventName + ' ' + showEventName );
+ };
+ };
+} )( mediaWiki, jQuery );
diff --git a/resources/src/mediawiki/mediawiki.content.json.css b/resources/src/mediawiki/mediawiki.content.json.css
index d93e291e..9e20264f 100644
--- a/resources/src/mediawiki/mediawiki.content.json.css
+++ b/resources/src/mediawiki/mediawiki.content.json.css
@@ -18,19 +18,25 @@
padding: 0.5em 1em;
}
-.mw-json td {
- background-color: #eee;
- font-style: italic;
-}
-
-.mw-json .value {
+.mw-json .value,
+.mw-json-single-value {
background-color: #dcfae3;
font-family: monospace, monospace;
white-space: pre-wrap;
}
+.mw-json-single-value {
+ background-color: #eee;
+}
+
+.mw-json-empty {
+ background-color: #fff;
+ font-style: italic;
+}
+
.mw-json tr {
margin-bottom: 0.5em;
+ background-color: #eee;
}
.mw-json th {
diff --git a/resources/src/mediawiki/mediawiki.cookie.js b/resources/src/mediawiki/mediawiki.cookie.js
index 6f9f0abb..8f091e4d 100644
--- a/resources/src/mediawiki/mediawiki.cookie.js
+++ b/resources/src/mediawiki/mediawiki.cookie.js
@@ -27,13 +27,14 @@
* @param {string|null} value Value of cookie. If `value` is `null` then this method will
* instead remove a cookie by name of `key`.
* @param {Object|Date} [options] Options object, or expiry date
- * @param {Date|null} [options.expires=wgCookieExpiration] The expiry date of the cookie.
+ * @param {Date|number|null} [options.expires] The expiry date of the cookie, or lifetime in seconds.
*
- * Default cookie expiration is based on `wgCookieExpiration`. If `wgCookieExpiration` is
- * 0, a session cookie is set (expires when the browser is closed). For non-zero values of
- * `wgCookieExpiration`, the cookie expires `wgCookieExpiration` seconds from now.
+ * If `options.expires` is null, then a session cookie is set.
+ *
+ * By default cookie expiration is based on `wgCookieExpiration`. Similar to `WebResponse`
+ * in PHP, we set a session cookie if `wgCookieExpiration` is 0. And for non-zero values
+ * it is interpreted as lifetime in seconds.
*
- * If options.expires is null, then a session cookie is set.
* @param {string} [options.prefix=wgCookiePrefix] The prefix of the key
* @param {string} [options.domain=wgCookieDomain] The domain attribute of the cookie
* @param {string} [options.path=wgCookiePath] The path attribute of the cookie
@@ -69,16 +70,20 @@
options = $.extend( defaultOptions, options );
}
- // $.cookie makes session cookies when expiry is omitted,
- // however our default is to expire wgCookieExpiration seconds from now.
- // Note: If wgCookieExpiration is 0, that is considered a special value indicating
+ // Default to using wgCookieExpiration (lifetime in seconds).
+ // If wgCookieExpiration is 0, that is considered a special value indicating
// all cookies should be session cookies by default.
if ( options.expires === undefined && config.wgCookieExpiration !== 0 ) {
date = new Date();
date.setTime( Number( date ) + ( config.wgCookieExpiration * 1000 ) );
options.expires = date;
+ } else if ( typeof options.expires === 'number' ) {
+ // Lifetime in seconds
+ date = new Date();
+ date.setTime( Number( date ) + ( options.expires * 1000 ) );
+ options.expires = date;
} else if ( options.expires === null ) {
- // $.cookie makes a session cookie when expires is omitted
+ // $.cookie makes a session cookie when options.expires is omitted
delete options.expires;
}
@@ -123,4 +128,4 @@
}
};
-} ( mediaWiki, jQuery ) );
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.debug.js b/resources/src/mediawiki/mediawiki.debug.js
index 4935984f..bdff99f7 100644
--- a/resources/src/mediawiki/mediawiki.debug.js
+++ b/resources/src/mediawiki/mediawiki.debug.js
@@ -170,8 +170,6 @@
paneTriggerBitDiv( 'includes', 'PHP includes', this.data.includes.length );
- paneTriggerBitDiv( 'profile', 'Profile', this.data.profile.length );
-
gitInfo = '';
if ( this.data.gitRevision !== false ) {
gitInfo = '(' + this.data.gitRevision.slice( 0, 7 ) + ')';
@@ -211,8 +209,7 @@
querylist: this.buildQueryTable(),
debuglog: this.buildDebugLogTable(),
request: this.buildRequestPane(),
- includes: this.buildIncludesPane(),
- profile: this.buildProfilePane()
+ includes: this.buildIncludesPane()
};
for ( id in panes ) {
@@ -381,10 +378,6 @@
}
return $table;
- },
-
- buildProfilePane: function () {
- return mw.Debug.profile.init();
}
};
diff --git a/resources/src/mediawiki/mediawiki.debug.profile.css b/resources/src/mediawiki/mediawiki.debug.profile.css
deleted file mode 100644
index ab27da9d..00000000
--- a/resources/src/mediawiki/mediawiki.debug.profile.css
+++ /dev/null
@@ -1,45 +0,0 @@
-.mw-debug-profile-tipsy .tipsy-inner {
- /* undo max-width from vector on .tipsy-inner */
- max-width: none;
- /* needed for some browsers to provide space for the scrollbar without wrapping text */
- min-width: 100%;
- max-height: 150px;
- overflow-y: auto;
-}
-
-.mw-debug-profile-underline {
- stroke-width: 1;
- stroke: #dfdfdf;
-}
-
-.mw-debug-profile-period {
- fill: red;
-}
-
-/* connecting line between endpoints on long events */
-.mw-debug-profile-period line {
- stroke: red;
- stroke-width: 2;
-}
-
-.mw-debug-profile-tipsy,
-.mw-debug-profile-timeline text {
- color: #444;
- fill: #444;
- /* using em's causes the two locations to have different sizes */
- font-size: 12px;
- font-family: sans-serif;
-}
-
-.mw-debug-profile-meta,
-.mw-debug-profile-timeline tspan {
- /* using em's causes the two locations to have different sizes */
- font-size: 10px;
-}
-
-.mw-debug-profile-no-data {
- text-align: center;
- padding-top: 5em;
- font-weight: bold;
- font-size: 1.2em;
-}
diff --git a/resources/src/mediawiki/mediawiki.debug.profile.js b/resources/src/mediawiki/mediawiki.debug.profile.js
deleted file mode 100644
index 04f7acd0..00000000
--- a/resources/src/mediawiki/mediawiki.debug.profile.js
+++ /dev/null
@@ -1,556 +0,0 @@
-/*!
- * JavaScript for the debug toolbar profiler, enabled through $wgDebugToolbar
- * and StartProfiler.php.
- *
- * @author Erik Bernhardson
- * @since 1.23
- */
-
-( function ( mw, $ ) {
- 'use strict';
-
- /**
- * @singleton
- * @class mw.Debug.profile
- */
- var profile = mw.Debug.profile = {
- /**
- * Object containing data for the debug toolbar
- *
- * @property ProfileData
- */
- data: null,
-
- /**
- * @property DOMElement
- */
- container: null,
-
- /**
- * Initializes the profiling pane.
- */
- init: function ( data, width, mergeThresholdPx, dropThresholdPx ) {
- data = data || mw.config.get( 'debugInfo' ).profile;
- profile.width = width || $(window).width() - 20;
- // merge events from same pixel(some events are very granular)
- mergeThresholdPx = mergeThresholdPx || 2;
- // only drop events if requested
- dropThresholdPx = dropThresholdPx || 0;
-
- if (
- !Array.prototype.map ||
- !Array.prototype.reduce ||
- !Array.prototype.filter ||
- !document.createElementNS ||
- !document.createElementNS.bind
- ) {
- profile.container = profile.buildRequiresBrowserFeatures();
- } else if ( data.length === 0 ) {
- profile.container = profile.buildNoData();
- } else {
- // Initialize createSvgElement (now that we know we have
- // document.createElementNS and bind)
- this.createSvgElement = document.createElementNS.bind( document, 'http://www.w3.org/2000/svg' );
-
- // generate a flyout
- profile.data = new ProfileData( data, profile.width, mergeThresholdPx, dropThresholdPx );
- // draw it
- profile.container = profile.buildSvg( profile.container );
- profile.attachFlyout();
- }
-
- return profile.container;
- },
-
- buildRequiresBrowserFeatures: function () {
- return $( '<div>' )
- .text( 'Certain browser features, including parts of ECMAScript 5 and document.createElementNS, are required for the profile visualization.' )
- .get( 0 );
- },
-
- buildNoData: function () {
- return $( '<div>' ).addClass( 'mw-debug-profile-no-data' )
- .text( 'No events recorded, ensure profiling is enabled in StartProfiler.php.' )
- .get( 0 );
- },
-
- /**
- * Creates DOM nodes appropriately namespaced for SVG.
- * Initialized in init after checking support
- *
- * @param string tag to create
- * @return DOMElement
- */
- createSvgElement: null,
-
- /**
- * @param DOMElement|undefined
- */
- buildSvg: function ( node ) {
- var container, group, i, g,
- timespan = profile.data.timespan,
- gapPerEvent = 38,
- space = 10.5,
- currentHeight = space,
- totalHeight = 0;
-
- profile.ratio = ( profile.width - space * 2 ) / ( timespan.end - timespan.start );
- totalHeight += gapPerEvent * profile.data.groups.length;
-
- if ( node ) {
- $( node ).empty();
- } else {
- node = profile.createSvgElement( 'svg' );
- node.setAttribute( 'version', '1.2' );
- node.setAttribute( 'baseProfile', 'tiny' );
- }
- node.style.height = totalHeight;
- node.style.width = profile.width;
-
- // use a container that can be transformed
- container = profile.createSvgElement( 'g' );
- node.appendChild( container );
-
- for ( i = 0; i < profile.data.groups.length; i++ ) {
- group = profile.data.groups[i];
- g = profile.buildTimeline( group );
-
- g.setAttribute( 'transform', 'translate( 0 ' + currentHeight + ' )' );
- container.appendChild( g );
-
- currentHeight += gapPerEvent;
- }
-
- return node;
- },
-
- /**
- * @param Object group of periods to transform into graphics
- */
- buildTimeline: function ( group ) {
- var text, tspan, line, i,
- sum = group.timespan.sum,
- ms = ' ~ ' + ( sum < 1 ? sum.toFixed( 2 ) : sum.toFixed( 0 ) ) + ' ms',
- timeline = profile.createSvgElement( 'g' );
-
- timeline.setAttribute( 'class', 'mw-debug-profile-timeline' );
-
- // draw label
- text = profile.createSvgElement( 'text' );
- text.setAttribute( 'x', profile.xCoord( group.timespan.start ) );
- text.setAttribute( 'y', 0 );
- text.textContent = group.name;
- timeline.appendChild( text );
-
- // draw metadata
- tspan = profile.createSvgElement( 'tspan' );
- tspan.textContent = ms;
- text.appendChild( tspan );
-
- // draw timeline periods
- for ( i = 0; i < group.periods.length; i++ ) {
- timeline.appendChild( profile.buildPeriod( group.periods[i] ) );
- }
-
- // full-width line under each timeline
- line = profile.createSvgElement( 'line' );
- line.setAttribute( 'class', 'mw-debug-profile-underline' );
- line.setAttribute( 'x1', 0 );
- line.setAttribute( 'y1', 28 );
- line.setAttribute( 'x2', profile.width );
- line.setAttribute( 'y2', 28 );
- timeline.appendChild( line );
-
- return timeline;
- },
-
- /**
- * @param Object period to transform into graphics
- */
- buildPeriod: function ( period ) {
- var node,
- head = profile.xCoord( period.start ),
- tail = profile.xCoord( period.end ),
- g = profile.createSvgElement( 'g' );
-
- g.setAttribute( 'class', 'mw-debug-profile-period' );
- $( g ).data( 'period', period );
-
- if ( head + 16 > tail ) {
- node = profile.createSvgElement( 'rect' );
- node.setAttribute( 'x', head );
- node.setAttribute( 'y', 8 );
- node.setAttribute( 'width', 2 );
- node.setAttribute( 'height', 9 );
- g.appendChild( node );
-
- node = profile.createSvgElement( 'rect' );
- node.setAttribute( 'x', head );
- node.setAttribute( 'y', 8 );
- node.setAttribute( 'width', ( period.end - period.start ) * profile.ratio || 2 );
- node.setAttribute( 'height', 6 );
- g.appendChild( node );
- } else {
- node = profile.createSvgElement( 'polygon' );
- node.setAttribute( 'points', pointList( [
- [ head, 8 ],
- [ head, 19 ],
- [ head + 8, 8 ],
- [ head, 8]
- ] ) );
- g.appendChild( node );
-
- node = profile.createSvgElement( 'polygon' );
- node.setAttribute( 'points', pointList( [
- [ tail, 8 ],
- [ tail, 19 ],
- [ tail - 8, 8 ],
- [ tail, 8 ]
- ] ) );
- g.appendChild( node );
-
- node = profile.createSvgElement( 'line' );
- node.setAttribute( 'x1', head );
- node.setAttribute( 'y1', 9 );
- node.setAttribute( 'x2', tail );
- node.setAttribute( 'y2', 9 );
- g.appendChild( node );
- }
-
- return g;
- },
-
- /**
- * @param Object
- */
- buildFlyout: function ( period ) {
- var contained, sum, ms, mem, i,
- node = $( '<div>' );
-
- for ( i = 0; i < period.contained.length; i++ ) {
- contained = period.contained[i];
- sum = contained.end - contained.start;
- ms = '' + ( sum < 1 ? sum.toFixed( 2 ) : sum.toFixed( 0 ) ) + ' ms';
- mem = formatBytes( contained.memory );
-
- $( '<div>' ).text( contained.source.name )
- .append( $( '<span>' ).text( ' ~ ' + ms + ' / ' + mem ).addClass( 'mw-debug-profile-meta' ) )
- .appendTo( node );
- }
-
- return node;
- },
-
- /**
- * Attach a hover flyout to all .mw-debug-profile-period groups.
- */
- attachFlyout: function () {
- // for some reason addClass and removeClass from jQuery
- // arn't working on svg elements in chrome <= 33.0 (possibly more)
- var $container = $( profile.container ),
- addClass = function ( node, value ) {
- var current = node.getAttribute( 'class' ),
- list = current ? current.split( ' ' ) : false,
- idx = list ? list.indexOf( value ) : -1;
-
- if ( idx === -1 ) {
- node.setAttribute( 'class', current ? ( current + ' ' + value ) : value );
- }
- },
- removeClass = function ( node, value ) {
- var current = node.getAttribute( 'class' ),
- list = current ? current.split( ' ' ) : false,
- idx = list ? list.indexOf( value ) : -1;
-
- if ( idx !== -1 ) {
- list.splice( idx, 1 );
- node.setAttribute( 'class', list.join( ' ' ) );
- }
- },
- // hide all tipsy flyouts
- hide = function () {
- $container.find( '.mw-debug-profile-period.tipsy-visible' )
- .each( function () {
- removeClass( this, 'tipsy-visible' );
- $( this ).tipsy( 'hide' );
- } );
- };
-
- $container.find( '.mw-debug-profile-period' ).tipsy( {
- fade: true,
- gravity: function () {
- return $.fn.tipsy.autoNS.call( this ) + $.fn.tipsy.autoWE.call( this );
- },
- className: 'mw-debug-profile-tipsy',
- center: false,
- html: true,
- trigger: 'manual',
- title: function () {
- return profile.buildFlyout( $( this ).data( 'period' ) ).html();
- }
- } ).on( 'mouseenter', function () {
- hide();
- addClass( this, 'tipsy-visible' );
- $( this ).tipsy( 'show' );
- } );
-
- $container.on( 'mouseleave', function ( event ) {
- var $from = $( event.relatedTarget ),
- $to = $( event.target );
- // only close the tipsy if we are not
- if ( $from.closest( '.tipsy' ).length === 0 &&
- $to.closest( '.tipsy' ).length === 0 &&
- $to.get( 0 ).namespaceURI !== 'http://www.w4.org/2000/svg'
- ) {
- hide();
- }
- } ).on( 'click', function () {
- // convenience method for closing
- hide();
- } );
- },
-
- /**
- * @return number the x co-ordinate for the specified timestamp
- */
- xCoord: function ( msTimestamp ) {
- return ( msTimestamp - profile.data.timespan.start ) * profile.ratio;
- }
- };
-
- function ProfileData( data, width, mergeThresholdPx, dropThresholdPx ) {
- // validate input data
- this.data = data.map( function ( event ) {
- event.periods = event.periods.filter( function ( period ) {
- return period.start && period.end
- && period.start < period.end
- // period start must be a reasonable ms timestamp
- && period.start > 1000000;
- } );
- return event;
- } ).filter( function ( event ) {
- return event.name && event.periods.length > 0;
- } );
-
- // start and end time of the data
- this.timespan = this.data.reduce( function ( result, event ) {
- return event.periods.reduce( periodMinMax, result );
- }, periodMinMax.initial() );
-
- // transform input data
- this.groups = this.collate( width, mergeThresholdPx, dropThresholdPx );
-
- return this;
- }
-
- /**
- * There are too many unique events to display a line for each,
- * so this does a basic grouping.
- */
- ProfileData.groupOf = function ( label ) {
- var pos, prefix = 'Profile section ended by close(): ';
- if ( label.indexOf( prefix ) === 0 ) {
- label = label.slice( prefix.length );
- }
-
- pos = [ '::', ':', '-' ].reduce( function ( result, separator ) {
- var pos = label.indexOf( separator );
- if ( pos === -1 ) {
- return result;
- } else if ( result === -1 ) {
- return pos;
- } else {
- return Math.min( result, pos );
- }
- }, -1 );
-
- if ( pos === -1 ) {
- return label;
- } else {
- return label.slice( 0, pos );
- }
- };
-
- /**
- * @return Array list of objects with `name` and `events` keys
- */
- ProfileData.groupEvents = function ( events ) {
- var group, i,
- groups = {};
-
- // Group events together
- for ( i = events.length - 1; i >= 0; i-- ) {
- group = ProfileData.groupOf( events[i].name );
- if ( groups[group] ) {
- groups[group].push( events[i] );
- } else {
- groups[group] = [events[i]];
- }
- }
-
- // Return an array of groups
- return Object.keys( groups ).map( function ( group ) {
- return {
- name: group,
- events: groups[group]
- };
- } );
- };
-
- ProfileData.periodSorter = function ( a, b ) {
- if ( a.start === b.start ) {
- return a.end - b.end;
- }
- return a.start - b.start;
- };
-
- ProfileData.genMergePeriodReducer = function ( mergeThresholdMs ) {
- return function ( result, period ) {
- if ( result.length === 0 ) {
- // period is first result
- return [{
- start: period.start,
- end: period.end,
- contained: [period]
- }];
- }
- var last = result[result.length - 1];
- if ( period.end < last.end ) {
- // end is contained within previous
- result[result.length - 1].contained.push( period );
- } else if ( period.start - mergeThresholdMs < last.end ) {
- // neighbors within merging distance
- result[result.length - 1].end = period.end;
- result[result.length - 1].contained.push( period );
- } else {
- // period is next result
- result.push( {
- start: period.start,
- end: period.end,
- contained: [period]
- } );
- }
- return result;
- };
- };
-
- /**
- * Collect all periods from the grouped events and apply merge and
- * drop transformations
- */
- ProfileData.extractPeriods = function ( events, mergeThresholdMs, dropThresholdMs ) {
- // collect the periods from all events
- return events.reduce( function ( result, event ) {
- if ( !event.periods.length ) {
- return result;
- }
- result.push.apply( result, event.periods.map( function ( period ) {
- // maintain link from period to event
- period.source = event;
- return period;
- } ) );
- return result;
- }, [] )
- // sort combined periods
- .sort( ProfileData.periodSorter )
- // Apply merge threshold. Original periods
- // are maintained in the `contained` property
- .reduce( ProfileData.genMergePeriodReducer( mergeThresholdMs ), [] )
- // Apply drop threshold
- .filter( function ( period ) {
- return period.end - period.start > dropThresholdMs;
- } );
- };
-
- /**
- * runs a callback on all periods in the group. Only valid after
- * groups.periods[0..n].contained are populated. This runs against
- * un-transformed data and is better suited to summing or other
- * stat collection
- */
- ProfileData.reducePeriods = function ( group, callback, result ) {
- return group.periods.reduce( function ( result, period ) {
- return period.contained.reduce( callback, result );
- }, result );
- };
-
- /**
- * Transforms this.data grouping by labels, merging neighboring
- * events in the groups, and drops events and groups below the
- * display threshold. Groups are returned sorted by starting time.
- */
- ProfileData.prototype.collate = function ( width, mergeThresholdPx, dropThresholdPx ) {
- // ms to pixel ratio
- var ratio = ( this.timespan.end - this.timespan.start ) / width,
- // transform thresholds to ms
- mergeThresholdMs = mergeThresholdPx * ratio,
- dropThresholdMs = dropThresholdPx * ratio;
-
- return ProfileData.groupEvents( this.data )
- // generate data about the grouped events
- .map( function ( group ) {
- // Cleaned periods from all events
- group.periods = ProfileData.extractPeriods( group.events, mergeThresholdMs, dropThresholdMs );
- // min and max timestamp per group
- group.timespan = ProfileData.reducePeriods( group, periodMinMax, periodMinMax.initial() );
- // ms from first call to end of last call
- group.timespan.length = group.timespan.end - group.timespan.start;
- // collect the un-transformed periods
- group.timespan.sum = ProfileData.reducePeriods( group, function ( result, period ) {
- result.push( period );
- return result;
- }, [] )
- // sort by start time
- .sort( ProfileData.periodSorter )
- // merge overlapping
- .reduce( ProfileData.genMergePeriodReducer( 0 ), [] )
- // sum
- .reduce( function ( result, period ) {
- return result + period.end - period.start;
- }, 0 );
-
- return group;
- }, this )
- // remove groups that have had all their periods filtered
- .filter( function ( group ) {
- return group.periods.length > 0;
- } )
- // sort events by first start
- .sort( function ( a, b ) {
- return ProfileData.periodSorter( a.timespan, b.timespan );
- } );
- };
-
- // reducer to find edges of period array
- function periodMinMax( result, period ) {
- if ( period.start < result.start ) {
- result.start = period.start;
- }
- if ( period.end > result.end ) {
- result.end = period.end;
- }
- return result;
- }
-
- periodMinMax.initial = function () {
- return { start: Number.POSITIVE_INFINITY, end: Number.NEGATIVE_INFINITY };
- };
-
- function formatBytes( bytes ) {
- var i, sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
- if ( bytes === 0 ) {
- return '0 Bytes';
- }
- i = parseInt( Math.floor( Math.log( bytes ) / Math.log( 1024 ) ), 10 );
- return Math.round( bytes / Math.pow( 1024, i ), 2 ) + ' ' + sizes[i];
- }
-
- // turns a 2d array into a point list for svg
- // polygon points attribute
- // ex: [[1,2],[3,4],[4,2]] = '1,2 3,4 4,2'
- function pointList( pairs ) {
- return pairs.map( function ( pair ) {
- return pair.join( ',' );
- } ).join( ' ' );
- }
-}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.errorLogger.js b/resources/src/mediawiki/mediawiki.errorLogger.js
new file mode 100644
index 00000000..9f4f19dd
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.errorLogger.js
@@ -0,0 +1,49 @@
+/**
+ * Try to catch errors in modules which don't do their own error handling.
+ * @class mw.errorLogger
+ * @singleton
+ */
+( function ( mw ) {
+ 'use strict';
+
+ mw.errorLogger = {
+ /**
+ * Fired via mw.track when an error is not handled by local code and is caught by the
+ * window.onerror handler.
+ *
+ * @event global_error
+ * @param {string} errorMessage Error errorMessage.
+ * @param {string} url URL where error was raised.
+ * @param {number} lineNumber Line number where error was raised.
+ * @param {number} [columnNumber] Line number where error was raised. Not all browsers
+ * support this.
+ * @param {Error|Mixed} [errorObject] The error object. Typically an instance of Error, but anything
+ * (even a primitive value) passed to a throw clause will end up here.
+ */
+
+ /**
+ * Install a window.onerror handler that will report via mw.track, while preserving
+ * any previous handler.
+ * @param {Object} window
+ */
+ installGlobalHandler: function ( window ) {
+ // We will preserve the return value of the previous handler. window.onerror works the
+ // opposite way than normal event handlers (returning true will prevent the default
+ // action, returning false will let the browser handle the error normally, by e.g.
+ // logging to the console), so our fallback old handler needs to return false.
+ var oldHandler = window.onerror || function () { return false; };
+
+ /**
+ * Dumb window.onerror handler which forwards the errors via mw.track.
+ * @fires global_error
+ */
+ window.onerror = function ( errorMessage, url, lineNumber, columnNumber, errorObject ) {
+ mw.track( 'global.error', { errorMessage: errorMessage, url: url,
+ lineNumber: lineNumber, columnNumber: columnNumber, errorObject: errorObject } );
+ return oldHandler.apply( this, arguments );
+ };
+ }
+ };
+
+ mw.errorLogger.installGlobalHandler( window );
+}( mediaWiki ) );
diff --git a/resources/src/mediawiki/mediawiki.feedback.css b/resources/src/mediawiki/mediawiki.feedback.css
index 6bd47bb2..f2859db3 100644
--- a/resources/src/mediawiki/mediawiki.feedback.css
+++ b/resources/src/mediawiki/mediawiki.feedback.css
@@ -7,3 +7,16 @@
width: 18px;
height: 18px;
}
+
+.mw-feedbackDialog-welcome-message,
+.mw-feedbackDialog-feedback-terms {
+ line-height: 1.2em;
+}
+
+.mw-feedbackDialog-feedback-form {
+ margin-top: 1em;
+}
+
+.mw-feedbackDialog-feedback-termsofuse {
+ margin-left: 2.5em;
+}
diff --git a/resources/src/mediawiki/mediawiki.feedback.js b/resources/src/mediawiki/mediawiki.feedback.js
index 1c0d8332..d9401001 100644
--- a/resources/src/mediawiki/mediawiki.feedback.js
+++ b/resources/src/mediawiki/mediawiki.feedback.js
@@ -3,8 +3,11 @@
*
* @author Ryan Kaldari, 2010
* @author Neil Kandalgaonkar, 2010-11
+ * @author Moriel Schottlender, 2015
* @since 1.19
*/
+/*jshint es3:false */
+/*global OO*/
( function ( mw, $ ) {
/**
* This is a way of getting simple feedback from users. It's useful
@@ -32,289 +35,469 @@
*
* @class
* @constructor
- * @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
+ * @param {Object} [config] Configuration object
+ * @cfg {mw.Title} [title="Feedback"] The title of the page where you collect
+ * feedback.
+ * @cfg {string} [dialogTitleMessageKey="feedback-dialog-title"] Message key for the
+ * title of the dialog box
+ * @cfg {mw.Uri|string} [bugsLink="//phabricator.wikimedia.org/maniphest/task/create/"] URL where
+ * bugs can be posted
+ * @cfg {mw.Uri|string} [bugsListLink="//phabricator.wikimedia.org/maniphest/query/advanced"] URL
+ * where bugs can be listed
+ * @cfg {boolean} [showUseragentCheckbox=false] Show a Useragent agreement checkbox as part of the form.
+ * @cfg {boolean} [useragentCheckboxMandatory=false] Make the Useragent checkbox mandatory.
+ * @cfg {string|jQuery} [useragentCheckboxMessage] Supply a custom message for the useragent checkbox.
+ * defaults to the message 'feedback-terms'.
*/
- mw.Feedback = function ( options ) {
- if ( options === undefined ) {
- options = {};
- }
+ mw.Feedback = function MwFeedback( config ) {
+ config = config || {};
- if ( options.api === undefined ) {
- options.api = new mw.Api();
- }
+ this.dialogTitleMessageKey = config.dialogTitleMessageKey || 'feedback-dialog-title';
- if ( options.title === undefined ) {
- options.title = new mw.Title( 'Feedback' );
- }
+ // Feedback page title
+ this.feedbackPageTitle = config.title || new mw.Title( 'Feedback' );
- if ( options.dialogTitleMessageKey === undefined ) {
- options.dialogTitleMessageKey = 'feedback-submit';
- }
+ this.messagePosterPromise = mw.messagePoster.factory.create( this.feedbackPageTitle );
- if ( options.bugsLink === undefined ) {
- options.bugsLink = '//bugzilla.wikimedia.org/enter_bug.cgi';
- }
+ // Links
+ this.bugsTaskSubmissionLink = config.bugsLink || '//phabricator.wikimedia.org/maniphest/task/create/';
+ this.bugsTaskListLink = config.bugsListLink || '//phabricator.wikimedia.org/maniphest/query/advanced';
- if ( options.bugsListLink === undefined ) {
- options.bugsListLink = '//bugzilla.wikimedia.org/query.cgi';
- }
+ // Terms of use
+ this.useragentCheckboxShow = !!config.showUseragentCheckbox;
+ this.useragentCheckboxMandatory = !!config.useragentCheckboxMandatory;
+ this.useragentCheckboxMessage = config.useragentCheckboxMessage ||
+ $( '<p>' ).append( mw.msg( 'feedback-terms' ) );
- $.extend( this, options );
- this.setup();
+ // Message dialog
+ this.thankYouDialog = new OO.ui.MessageDialog();
};
- mw.Feedback.prototype = {
- /**
- * Sets up interface
- */
- setup: function () {
- var $feedbackPageLink,
- $bugNoteLink,
- $bugsListLink,
- fb = this;
-
- $feedbackPageLink = $( '<a>' )
- .attr( {
- href: fb.title.getUrl(),
- target: '_blank'
- } )
- .css( {
- whiteSpace: 'nowrap'
- } );
+ /* Initialize */
+ OO.initClass( mw.Feedback );
- $bugNoteLink = $( '<a>' ).attr( { href: '#' } ).click( function () {
- fb.displayBugs();
- } );
-
- $bugsListLink = $( '<a>' ).attr( {
- href: fb.bugsListLink,
- target: '_blank'
- } );
-
- // TODO: Use a stylesheet instead of these inline styles
- this.$dialog =
- $( '<div style="position: relative;"></div>' ).append(
- $( '<div class="feedback-mode feedback-form"></div>' ).append(
- $( '<small>' ).append(
- $( '<p>' ).msg(
- 'feedback-bugornote',
- $bugNoteLink,
- fb.title.getNameText(),
- $feedbackPageLink.clone()
- )
- ),
- $( '<div style="margin-top: 1em;"></div>' )
- .msg( 'feedback-subject' )
- .append(
- $( '<br>' ),
- $( '<input type="text" class="feedback-subject" name="subject" maxlength="60" style="width: 100%; -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;"/>' )
- ),
- $( '<div style="margin-top: 0.4em;"></div>' )
- .msg( 'feedback-message' )
- .append(
- $( '<br>' ),
- $( '<textarea name="message" class="feedback-message" rows="5" cols="60"></textarea>' )
- )
- ),
- $( '<div class="feedback-mode feedback-bugs"></div>' ).append(
- $( '<p>' ).msg( 'feedback-bugcheck', $bugsListLink )
- ),
- $( '<div class="feedback-mode feedback-submitting" style="text-align: center; margin: 3em 0;"></div>' )
- .msg( 'feedback-adding' )
- .append(
- $( '<br>' ),
- $( '<span class="feedback-spinner"></span>' )
- ),
- $( '<div class="feedback-mode feedback-thanks" style="text-align: center; margin:1em"></div>' ).msg(
- 'feedback-thanks', fb.title.getNameText(), $feedbackPageLink.clone()
+ /* Static Properties */
+ mw.Feedback.static.windowManager = null;
+ mw.Feedback.static.dialog = null;
+
+ /* Methods */
+
+ /**
+ * Respond to dialog submit event. If the information was
+ * submitted, either successfully or with an error, open
+ * a MessageDialog to thank the user.
+ * @param {string} [status] A status of the end of operation
+ * of the main feedback dialog. Empty if the dialog was
+ * dismissed with no action or the user followed the button
+ * to the external task reporting site.
+ */
+ mw.Feedback.prototype.onDialogSubmit = function ( status ) {
+ var dialogConfig = {};
+ switch ( status ) {
+ case 'submitted':
+ dialogConfig = {
+ title: mw.msg( 'feedback-thanks-title' ),
+ message: $( '<span>' ).append(
+ mw.message(
+ 'feedback-thanks',
+ this.feedbackPageTitle.getNameText(),
+ $( '<a>' )
+ .attr( {
+ target: '_blank',
+ href: this.feedbackPageTitle.getUrl()
+ } )
+ ).parse()
),
- $( '<div class="feedback-mode feedback-error" style="position: relative;"></div>' ).append(
- $( '<div class="feedback-error-msg style="color: #990000; margin-top: 0.4em;"></div>' )
- )
- );
+ actions: [
+ {
+ action: 'accept',
+ label: mw.msg( 'feedback-close' ),
+ flags: 'primary'
+ }
+ ]
+ };
+ break;
+ case 'error1':
+ case 'error2':
+ case 'error3':
+ case 'error4':
+ dialogConfig = {
+ title: mw.msg( 'feedback-error-title' ),
+ message: mw.msg( 'feedback-' + status ),
+ actions: [
+ {
+ action: 'accept',
+ label: mw.msg( 'feedback-close' ),
+ flags: 'primary'
+ }
+ ]
+ };
+ break;
+ }
- this.$dialog.dialog( {
- width: 500,
- autoOpen: false,
- title: mw.message( this.dialogTitleMessageKey ).escaped(),
- modal: true,
- buttons: fb.buttons
- } );
+ // Show the message dialog
+ if ( !$.isEmptyObject( dialogConfig ) ) {
+ this.constructor.static.windowManager.openWindow(
+ this.thankYouDialog,
+ dialogConfig
+ );
+ }
+ };
- this.subjectInput = this.$dialog.find( 'input.feedback-subject' ).get( 0 );
- this.messageInput = this.$dialog.find( 'textarea.feedback-message' ).get( 0 );
- },
+ /**
+ * Modify the display form, and then open it, focusing interface on the subject.
+ *
+ * @param {Object} [contents] Prefilled contents for the feedback form.
+ * @param {string} [contents.subject] The subject of the feedback, as plaintext
+ * @param {string} [contents.message] The content of the feedback, as wikitext
+ */
+ mw.Feedback.prototype.launch = function ( contents ) {
+ // Dialog
+ if ( !this.constructor.static.dialog ) {
+ this.constructor.static.dialog = new mw.Feedback.Dialog();
+ this.constructor.static.dialog.connect( this, { submit: 'onDialogSubmit' } );
+ }
+ if ( !this.constructor.static.windowManager ) {
+ this.constructor.static.windowManager = new OO.ui.WindowManager();
+ this.constructor.static.windowManager.addWindows( [
+ this.constructor.static.dialog,
+ this.thankYouDialog
+ ] );
+ $( 'body' )
+ .append( this.constructor.static.windowManager.$element );
+ }
+ // Open the dialog
+ this.constructor.static.windowManager.openWindow(
+ this.constructor.static.dialog,
+ {
+ title: mw.msg( this.dialogTitleMessageKey ),
+ settings: {
+ messagePosterPromise: this.messagePosterPromise,
+ title: this.feedbackPageTitle,
+ dialogTitleMessageKey: this.dialogTitleMessageKey,
+ bugsTaskSubmissionLink: this.bugsTaskSubmissionLink,
+ bugsTaskListLink: this.bugsTaskListLink,
+ useragentCheckbox: {
+ show: this.useragentCheckboxShow,
+ mandatory: this.useragentCheckboxMandatory,
+ message: this.useragentCheckboxMessage
+ }
+ },
+ contents: contents
+ }
+ );
+ };
- /**
- * Displays a section of the dialog.
- *
- * @param {"form"|"bugs"|"submitting"|"thanks"|"error"} s
- * The section of the dialog to show.
- */
- display: function ( s ) {
- // Hide the buttons
- this.$dialog.dialog( { buttons: {} } );
- // Hide everything
- this.$dialog.find( '.feedback-mode' ).hide();
- // Show the desired div
- this.$dialog.find( '.feedback-' + s ).show();
- },
+ /**
+ * mw.Feedback Dialog
+ *
+ * @class
+ * @extends OO.ui.ProcessDialog
+ *
+ * @constructor
+ * @param {Object} config Configuration object
+ */
+ mw.Feedback.Dialog = function mwFeedbackDialog( config ) {
+ // Parent constructor
+ mw.Feedback.Dialog.super.call( this, config );
+
+ this.status = '';
+ this.feedbackPageTitle = null;
+ // Initialize
+ this.$element.addClass( 'mwFeedback-Dialog' );
+ };
- /**
- * Display the submitting section.
- */
- displaySubmitting: function () {
- this.display( 'submitting' );
+ OO.inheritClass( mw.Feedback.Dialog, OO.ui.ProcessDialog );
+
+ /* Static properties */
+ mw.Feedback.Dialog.static.name = 'mwFeedbackDialog';
+ mw.Feedback.Dialog.static.title = mw.msg( 'feedback-dialog-title' );
+ mw.Feedback.Dialog.static.size = 'medium';
+ mw.Feedback.Dialog.static.actions = [
+ {
+ action: 'submit',
+ label: mw.msg( 'feedback-submit' ),
+ flags: [ 'primary', 'constructive' ]
},
-
- /**
- * Display the bugs section.
- */
- displayBugs: function () {
- var fb = this,
- bugsButtons = {};
-
- this.display( 'bugs' );
- bugsButtons[ mw.msg( 'feedback-bugnew' ) ] = function () {
- window.open( fb.bugsLink, '_blank' );
- };
- bugsButtons[ mw.msg( 'feedback-cancel' ) ] = function () {
- fb.cancel();
- };
- this.$dialog.dialog( {
- buttons: bugsButtons
- } );
+ {
+ action: 'external',
+ label: mw.msg( 'feedback-external-bug-report-button' ),
+ flags: 'constructive'
},
+ {
+ action: 'cancel',
+ label: mw.msg( 'feedback-cancel' ),
+ flags: 'safe'
+ }
+ ];
- /**
- * Display the thanks section.
- */
- displayThanks: function () {
- var fb = this,
- closeButton = {};
-
- this.display( 'thanks' );
- closeButton[ mw.msg( 'feedback-close' ) ] = function () {
- fb.$dialog.dialog( 'close' );
- };
- this.$dialog.dialog( {
- buttons: closeButton
- } );
- },
+ /**
+ * @inheritdoc
+ */
+ mw.Feedback.Dialog.prototype.initialize = function () {
+ var feedbackSubjectFieldLayout, feedbackMessageFieldLayout,
+ feedbackFieldsetLayout, termsOfUseLabel;
+
+ // Parent method
+ mw.Feedback.Dialog.super.prototype.initialize.call( this );
+
+ this.feedbackPanel = new OO.ui.PanelLayout( {
+ scrollable: false,
+ expanded: false,
+ padded: true
+ } );
+
+ this.$spinner = $( '<div>' )
+ .addClass( 'feedback-spinner' );
+
+ // Feedback form
+ this.feedbackMessageLabel = new OO.ui.LabelWidget( {
+ classes: [ 'mw-feedbackDialog-welcome-message' ]
+ } );
+ this.feedbackSubjectInput = new OO.ui.TextInputWidget( {
+ multiline: false
+ } );
+ this.feedbackMessageInput = new OO.ui.TextInputWidget( {
+ autosize: true,
+ multiline: true
+ } );
+ feedbackSubjectFieldLayout = new OO.ui.FieldLayout( this.feedbackSubjectInput, {
+ label: mw.msg( 'feedback-subject' )
+ } );
+ feedbackMessageFieldLayout = new OO.ui.FieldLayout( this.feedbackMessageInput, {
+ label: mw.msg( 'feedback-message' )
+ } );
+ feedbackFieldsetLayout = new OO.ui.FieldsetLayout( {
+ items: [ feedbackSubjectFieldLayout, feedbackMessageFieldLayout ],
+ classes: [ 'mw-feedbackDialog-feedback-form' ]
+ } );
+
+ // Useragent terms of use
+ this.useragentCheckbox = new OO.ui.CheckboxInputWidget();
+ this.useragentFieldLayout = new OO.ui.FieldLayout( this.useragentCheckbox, {
+ classes: [ 'mw-feedbackDialog-feedback-terms' ],
+ align: 'inline'
+ } );
+
+ termsOfUseLabel = new OO.ui.LabelWidget( {
+ classes: [ 'mw-feedbackDialog-feedback-termsofuse' ],
+ label: $( '<p>' ).append( mw.msg( 'feedback-termsofuse' ) )
+ } );
+
+ this.feedbackPanel.$element.append(
+ this.feedbackMessageLabel.$element,
+ feedbackFieldsetLayout.$element,
+ this.useragentFieldLayout.$element,
+ termsOfUseLabel.$element
+ );
+
+ // Events
+ this.feedbackSubjectInput.connect( this, { change: 'validateFeedbackForm' } );
+ this.feedbackMessageInput.connect( this, { change: 'validateFeedbackForm' } );
+ this.feedbackMessageInput.connect( this, { change: 'updateSize' } );
+ this.useragentCheckbox.connect( this, { change: 'validateFeedbackForm' } );
+
+ this.$body.append( this.feedbackPanel.$element );
+ };
- /**
- * Display the feedback form
- * @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,
- formButtons = {};
-
- this.subjectInput.value = ( contents && contents.subject ) ? contents.subject : '';
- this.messageInput.value = ( contents && contents.message ) ? contents.message : '';
-
- this.display( 'form' );
-
- // Set up buttons for dialog box. We have to do it the hard way since the json keys are localized
- formButtons[ mw.msg( 'feedback-submit' ) ] = function () {
- fb.submit();
- };
- formButtons[ mw.msg( 'feedback-cancel' ) ] = function () {
- fb.cancel();
- };
- this.$dialog.dialog( { buttons: formButtons } ); // put the buttons back
- },
+ /**
+ * Validate the feedback form
+ */
+ mw.Feedback.Dialog.prototype.validateFeedbackForm = function () {
+ var isValid = (
+ (
+ !this.useragentMandatory ||
+ this.useragentCheckbox.isSelected()
+ ) &&
+ (
+ !!this.feedbackMessageInput.getValue() ||
+ !!this.feedbackSubjectInput.getValue()
+ )
+ );
+
+ this.actions.setAbilities( { submit: isValid } );
+ };
- /**
- * Display an error on the form.
- *
- * @param {string} message Should be a valid message key.
- */
- displayError: function ( message ) {
- var fb = this,
- closeButton = {};
-
- this.display( 'error' );
- this.$dialog.find( '.feedback-error-msg' ).msg( message );
- closeButton[ mw.msg( 'feedback-close' ) ] = function () {
- fb.$dialog.dialog( 'close' );
- };
- this.$dialog.dialog( { buttons: closeButton } );
- },
+ /**
+ * @inheritdoc
+ */
+ mw.Feedback.Dialog.prototype.getBodyHeight = function () {
+ return this.feedbackPanel.$element.outerHeight( true );
+ };
- /**
- * Close the feedback form.
- */
- cancel: function () {
- this.$dialog.dialog( 'close' );
- },
+ /**
+ * @inheritdoc
+ */
+ mw.Feedback.Dialog.prototype.getSetupProcess = function ( data ) {
+ return mw.Feedback.Dialog.super.prototype.getSetupProcess.call( this, data )
+ .next( function () {
+ var plainMsg, parsedMsg,
+ settings = data.settings;
+ data.contents = data.contents || {};
+
+ // Prefill subject/message
+ this.feedbackSubjectInput.setValue( data.contents.subject );
+ this.feedbackMessageInput.setValue( data.contents.message );
+
+ this.status = '';
+ this.messagePosterPromise = settings.messagePosterPromise;
+ this.setBugReportLink( settings.bugsTaskSubmissionLink );
+ this.feedbackPageTitle = settings.title;
+ this.feedbackPageName = settings.title.getNameText();
+ this.feedbackPageUrl = settings.title.getUrl();
+
+ // Useragent checkbox
+ if ( settings.useragentCheckbox.show ) {
+ this.useragentFieldLayout.setLabel( settings.useragentCheckbox.message );
+ }
- /**
- * Submit the feedback form.
- */
- submit: function () {
- var subject, message,
- fb = this;
-
- // Get the values to submit.
- subject = this.subjectInput.value;
-
- // We used to include "mw.html.escape( navigator.userAgent )" but there are legal issues
- // with posting this without their explicit consent
- message = this.messageInput.value;
- if ( message.indexOf( '~~~' ) === -1 ) {
- message += ' ~~~~';
- }
+ this.useragentMandatory = settings.useragentCheckbox.mandatory;
+ this.useragentFieldLayout.toggle( settings.useragentCheckbox.show );
+
+ // HACK: Setting a link in the messages doesn't work. There is already a report
+ // about this, and the bug report offers a somewhat hacky work around that
+ // includes setting a separate message to be parsed.
+ // We want to make sure the user can configure both the title of the page and
+ // a separate url, so this must be allowed to parse correctly.
+ // See https://phabricator.wikimedia.org/T49395#490610
+ mw.messages.set( {
+ 'feedback-dialog-temporary-message':
+ '<a href="' + this.feedbackPageUrl + '" target="_blank">' + this.feedbackPageName + '</a>'
+ } );
+ plainMsg = mw.message( 'feedback-dialog-temporary-message' ).plain();
+ mw.messages.set( { 'feedback-dialog-temporary-message-parsed': plainMsg } );
+ parsedMsg = mw.message( 'feedback-dialog-temporary-message-parsed' );
+ this.feedbackMessageLabel.setLabel(
+ // Double-parse
+ $( '<span>' )
+ .append( mw.message( 'feedback-dialog-intro', parsedMsg ).parse() )
+ );
- this.displaySubmitting();
-
- // Post the message, resolving redirects
- this.api.newSection(
- this.title,
- subject,
- message,
- { redirect: true }
- )
- .done( function ( result ) {
- if ( result.edit !== undefined ) {
- if ( result.edit.result === 'Success' ) {
- fb.displayThanks();
- } else {
- // unknown API result
- fb.displayError( 'feedback-error1' );
- }
- } else {
- // edit failed
- fb.displayError( 'feedback-error2' );
+ this.validateFeedbackForm();
+ }, this );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.Feedback.Dialog.prototype.getReadyProcess = function ( data ) {
+ return mw.Feedback.Dialog.super.prototype.getReadyProcess.call( this, data )
+ .next( function () {
+ this.feedbackSubjectInput.focus();
+ }, this );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.Feedback.Dialog.prototype.getActionProcess = function ( action ) {
+ if ( action === 'cancel' ) {
+ return new OO.ui.Process( function () {
+ this.close( { action: action } );
+ }, this );
+ } else if ( action === 'external' ) {
+ return new OO.ui.Process( function () {
+ // Open in a new window
+ window.open( this.getBugReportLink(), '_blank' );
+ // Close the dialog
+ this.close();
+ }, this );
+ } else if ( action === 'submit' ) {
+ return new OO.ui.Process( function () {
+ var fb = this,
+ userAgentMessage = ':' +
+ '<small>' +
+ mw.msg( 'feedback-useragent' ) +
+ ' ' +
+ mw.html.escape( navigator.userAgent ) +
+ '</small>\n\n',
+ subject = this.feedbackSubjectInput.getValue(),
+ message = this.feedbackMessageInput.getValue();
+
+ // Add user agent if checkbox is selected
+ if ( this.useragentCheckbox.isSelected() ) {
+ message = userAgentMessage + message;
}
- } )
- .fail( function () {
- // ajax request failed
- fb.displayError( 'feedback-error3' );
- } );
- },
- /**
- * Modify the display form, and then open it, focusing interface on the subject.
- * @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 );
- this.$dialog.dialog( 'open' );
- this.subjectInput.focus();
+ // Post the message
+ return this.messagePosterPromise.then( function ( poster ) {
+ return fb.postMessage( poster, subject, message );
+ }, function () {
+ fb.status = 'error4';
+ mw.log.warn( 'Feedback report failed because MessagePoster could not be fetched' );
+ } ).always( function () {
+ fb.close();
+ } );
+ }, this );
}
+ // Fallback to parent handler
+ return mw.Feedback.Dialog.super.prototype.getActionProcess.call( this, action );
};
+
+ /**
+ * Posts the message
+ *
+ * @private
+ *
+ * @param {mw.messagePoster.MessagePoster} poster Poster implementation used to leave feedback
+ * @param {string} subject Subject of message
+ * @param {string} message Body of message
+ * @return {jQuery.Promise} Promise representing success of message posting action
+ */
+ mw.Feedback.Dialog.prototype.postMessage = function ( poster, subject, message ) {
+ var fb = this;
+
+ return poster.post(
+ subject,
+ message
+ ).then( function () {
+ fb.status = 'submitted';
+ }, function ( mainCode, secondaryCode, details ) {
+ if ( mainCode === 'api-fail' ) {
+ if ( secondaryCode === 'http' ) {
+ fb.status = 'error3';
+ // ajax request failed
+ mw.log.warn( 'Feedback report failed with HTTP error: ' + details.textStatus );
+ } else {
+ fb.status = 'error2';
+ mw.log.warn( 'Feedback report failed with API error: ' + secondaryCode );
+ }
+ } else {
+ fb.status = 'error1';
+ }
+ } );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.Feedback.Dialog.prototype.getTeardownProcess = function ( data ) {
+ return mw.Feedback.Dialog.super.prototype.getTeardownProcess.call( this, data )
+ .first( function () {
+ this.emit( 'submit', this.status, this.feedbackPageName, this.feedbackPageUrl );
+ // Cleanup
+ this.status = '';
+ this.feedbackPageTitle = null;
+ this.feedbackSubjectInput.setValue( '' );
+ this.feedbackMessageInput.setValue( '' );
+ this.useragentCheckbox.setSelected( false );
+ }, this );
+ };
+
+ /**
+ * Set the bug report link
+ * @param {string} link Link to the external bug report form
+ */
+ mw.Feedback.Dialog.prototype.setBugReportLink = function ( link ) {
+ this.bugReportLink = link;
+ };
+
+ /**
+ * Get the bug report link
+ * @returns {string} Link to the external bug report form
+ */
+ mw.Feedback.Dialog.prototype.getBugReportLink = function () {
+ return this.bugReportLink;
+ };
+
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.filewarning.js b/resources/src/mediawiki/mediawiki.filewarning.js
new file mode 100644
index 00000000..882affe1
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.filewarning.js
@@ -0,0 +1,68 @@
+/*!
+ * mediawiki.filewarning
+ *
+ * @author Mark Holmquist, 2015
+ * @since 1.25
+ */
+/*global OO*/
+( function ( mw, $, oo ) {
+ var warningConfig = mw.config.get( 'wgFileWarning' ),
+ warningMessages = warningConfig.messages,
+ warningLink = warningConfig.link,
+ $origMimetype = $( '.fullMedia .fileInfo .mime-type' ),
+ $mimetype = $origMimetype.clone(),
+ $header = $( '<h3>' )
+ .addClass( 'mediawiki-filewarning-header empty' ),
+ $main = $( '<p>' )
+ .addClass( 'mediawiki-filewarning-main empty' ),
+ $info = $( '<a>' )
+ .addClass( 'mediawiki-filewarning-info empty' ),
+ $footer = $( '<p>' )
+ .addClass( 'mediawiki-filewarning-footer empty' ),
+ dialog = new oo.ui.PopupButtonWidget( {
+ classes: [ 'mediawiki-filewarning-anchor' ],
+ label: $mimetype,
+ flags: [ 'warning' ],
+ icon: 'alert',
+ framed: false,
+ popup: {
+ classes: [ 'mediawiki-filewarning' ],
+ padded: true,
+ width: 400,
+ $content: $header.add( $main ).add( $info ).add( $footer )
+ }
+ } );
+
+ function loadMessage( $target, message ) {
+ if ( message ) {
+ $target.removeClass( 'empty' )
+ .text( mw.message( message ).text() );
+ }
+ }
+
+ // The main message must be populated for the dialog to show.
+ if ( warningConfig && warningConfig.messages && warningConfig.messages.main ) {
+ $mimetype.addClass( 'has-warning' );
+
+ $origMimetype.replaceWith( dialog.$element );
+
+ if ( warningMessages ) {
+ loadMessage( $main, warningMessages.main );
+ loadMessage( $header, warningMessages.header );
+ loadMessage( $footer, warningMessages.footer );
+
+ if ( warningLink ) {
+ loadMessage( $info, warningMessages.info );
+ $info.attr( 'href', warningLink );
+ }
+ }
+
+ // Make OOUI open the dialog, it won't appear until the user
+ // hovers over the warning.
+ dialog.getPopup().toggle( true );
+
+ // Override toggle handler because we don't need it for this popup
+ // object at all. Sort of nasty, but it gets the job done.
+ dialog.getPopup().toggle = $.noop;
+ }
+}( mediaWiki, jQuery, OO ) );
diff --git a/resources/src/mediawiki/mediawiki.filewarning.less b/resources/src/mediawiki/mediawiki.filewarning.less
new file mode 100644
index 00000000..489ac428
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.filewarning.less
@@ -0,0 +1,29 @@
+@import "mediawiki.ui/variables"
+
+.mediawiki-filewarning {
+ display: none;
+
+ .mediawiki-filewarning-header {
+ padding: 0;
+ font-weight: 600;
+ }
+
+ .mediawiki-filewarning-footer {
+ color: #888888;
+ }
+
+ .empty {
+ display: none;
+ }
+
+ .mediawiki-filewarning-anchor:hover & {
+ display: block;
+ }
+}
+
+.mime-type {
+ &.has-warning {
+ font-weight: bold;
+ color: @colorMediumSevere;
+ }
+}
diff --git a/resources/src/mediawiki/mediawiki.helplink.less b/resources/src/mediawiki/mediawiki.helplink.less
new file mode 100644
index 00000000..dd6bf745
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.helplink.less
@@ -0,0 +1,11 @@
+@import "mediawiki.mixins";
+
+#mw-indicator-mw-helplink a {
+ .background-image-svg('images/help.svg', 'images/help.png');
+ background-repeat: no-repeat;
+ background-position: left center;
+ padding-left: 28px;
+ display: inline-block;
+ height: 24px;
+ line-height: 24px;
+}
diff --git a/resources/src/mediawiki/mediawiki.hlist.js b/resources/src/mediawiki/mediawiki.hlist.js
index 0bbf8fad..8ba57f6f 100644
--- a/resources/src/mediawiki/mediawiki.hlist.js
+++ b/resources/src/mediawiki/mediawiki.hlist.js
@@ -1,31 +1,15 @@
/*!
- * .hlist fallbacks for IE 6, 7 and 8.
+ * .hlist fallbacks for IE 8.
* @author [[User:Edokter]]
*/
( function ( mw, $ ) {
var profile = $.client.profile();
- if ( profile.name === 'msie' ) {
- if ( profile.versionNumber === 8 ) {
- /* IE 8: Add pseudo-selector class to last-child list items */
- mw.hook( 'wikipage.content' ).add( function ( $content ) {
- $content.find( '.hlist' ).find( 'dd:last-child, dt:last-child, li:last-child' )
- .addClass( 'hlist-last-child' );
- } );
- }
- else if ( profile.versionNumber <= 7 ) {
- /* IE 7 and below: Generate interpuncts and parentheses */
- mw.hook( 'wikipage.content' ).add( function ( $content ) {
- var $hlists = $content.find( '.hlist' );
- $hlists.find( 'dt:not(:last-child)' )
- .append( ': ' );
- $hlists.find( 'dd:not(:last-child)' )
- .append( '<b>·</b> ' );
- $hlists.find( 'li:not(:last-child)' )
- .append( '<b>·</b> ' );
- $hlists.find( 'dl dl, dl ol, dl ul, ol dl, ol ol, ol ul, ul dl, ul ol, ul ul' )
- .prepend( '( ' ).append( ') ' );
- } );
- }
+ if ( profile.name === 'msie' && profile.versionNumber === 8 ) {
+ /* Add pseudo-selector class to last-child list items */
+ mw.hook( 'wikipage.content' ).add( function ( $content ) {
+ $content.find( '.hlist' ).find( 'dd:last-child, dt:last-child, li:last-child' )
+ .addClass( 'hlist-last-child' );
+ } );
}
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.htmlform.js b/resources/src/mediawiki/mediawiki.htmlform.js
index 594800e1..4a4a97e9 100644
--- a/resources/src/mediawiki/mediawiki.htmlform.js
+++ b/resources/src/mediawiki/mediawiki.htmlform.js
@@ -237,7 +237,9 @@
} );
function enhance( $root ) {
- var $matrixTooltips, $autocomplete;
+ var $matrixTooltips, $autocomplete,
+ // cache the separator to avoid object creation on each keypress
+ colonSeparator = mw.message( 'colon-separator' ).text();
/**
* @ignore
@@ -261,6 +263,36 @@
handleSelectOrOther.call( this, true );
} );
+ // Add a dynamic max length to the reason field of SelectAndOther
+ // This checks the length together with the value from the select field
+ // When the reason list is changed and the bytelimit is longer than the allowed,
+ // nothing is done
+ $root
+ .find( '.mw-htmlform-select-and-other-field' )
+ .each( function () {
+ var $this = $( this ),
+ // find the reason list
+ $reasonList = $root.find( '#' + $this.data( 'id-select' ) ),
+ // cache the current selection to avoid expensive lookup
+ currentValReasonList = $reasonList.val();
+
+ $reasonList.change( function () {
+ currentValReasonList = $reasonList.val();
+ } );
+
+ $this.byteLimit( function ( input ) {
+ // Should be built the same as in HTMLSelectAndOtherField::loadDataFromRequest
+ var comment = currentValReasonList;
+ if ( comment === 'other' ) {
+ comment = input;
+ } else if ( input !== '' ) {
+ // Entry from drop down menu + additional comment
+ comment += colonSeparator + input;
+ }
+ return comment;
+ } );
+ } );
+
// Set up hide-if elements
$root.find( '.mw-htmlform-hide-if' ).each( function () {
var v, $fields, test, func,
@@ -368,12 +400,12 @@
}
// Add/remove cloner clones without having to resubmit the form
- $root.find( '.mw-htmlform-cloner-delete-button' ).click( function ( ev ) {
+ $root.find( '.mw-htmlform-cloner-delete-button' ).filter( ':input' ).click( function ( ev ) {
ev.preventDefault();
$( this ).closest( 'li.mw-htmlform-cloner-li' ).remove();
} );
- $root.find( '.mw-htmlform-cloner-create-button' ).click( function ( ev ) {
+ $root.find( '.mw-htmlform-cloner-create-button' ).filter( ':input' ).click( function ( ev ) {
var $ul, $li, html;
ev.preventDefault();
diff --git a/resources/src/mediawiki/mediawiki.inspect.js b/resources/src/mediawiki/mediawiki.inspect.js
index 8e9fc89f..22d3cbb3 100644
--- a/resources/src/mediawiki/mediawiki.inspect.js
+++ b/resources/src/mediawiki/mediawiki.inspect.js
@@ -7,6 +7,9 @@
/*jshint devel:true */
( function ( mw, $ ) {
+ var inspect,
+ hasOwn = Object.prototype.hasOwnProperty;
+
function sortByProperty( array, prop, descending ) {
var order = descending ? -1 : 1;
return array.sort( function ( a, b ) {
@@ -16,16 +19,20 @@
function humanSize( bytes ) {
if ( !$.isNumeric( bytes ) || bytes === 0 ) { return bytes; }
- var i = 0, units = [ '', ' kB', ' MB', ' GB', ' TB', ' PB' ];
+ var i = 0,
+ units = [ '', ' kB', ' MB', ' GB', ' TB', ' PB' ];
+
for ( ; bytes >= 1024; bytes /= 1024 ) { i++; }
- return bytes.toFixed( 1 ) + units[i];
+ // Maintain one decimal for kB and above, but don't
+ // add ".0" for bytes.
+ return bytes.toFixed( i > 0 ? 1 : 0 ) + units[i];
}
/**
* @class mw.inspect
* @singleton
*/
- var inspect = {
+ inspect = {
/**
* Return a map of all dependency relationships between loaded modules.
@@ -34,16 +41,21 @@
* two properties, 'requires' and 'requiredBy'.
*/
getDependencyGraph: function () {
- var modules = inspect.getLoadedModules(), graph = {};
+ var modules = inspect.getLoadedModules(),
+ graph = {};
$.each( modules, function ( moduleIndex, moduleName ) {
var dependencies = mw.loader.moduleRegistry[moduleName].dependencies || [];
- graph[moduleName] = graph[moduleName] || { requiredBy: [] };
+ if ( !hasOwn.call( graph, moduleName ) ) {
+ graph[moduleName] = { requiredBy: [] };
+ }
graph[moduleName].requires = dependencies;
$.each( dependencies, function ( depIndex, depName ) {
- graph[depName] = graph[depName] || { requiredBy: [] };
+ if ( !hasOwn.call( graph, depName ) ) {
+ graph[depName] = { requiredBy: [] };
+ }
graph[depName].requiredBy.push( moduleName );
} );
} );
diff --git a/resources/src/mediawiki/mediawiki.jqueryMsg.js b/resources/src/mediawiki/mediawiki.jqueryMsg.js
index ad71b083..79939f64 100644
--- a/resources/src/mediawiki/mediawiki.jqueryMsg.js
+++ b/resources/src/mediawiki/mediawiki.jqueryMsg.js
@@ -136,7 +136,7 @@
* Returns a function suitable for use as a global, to construct strings from the message key (and optional replacements).
* e.g.
*
- * window.gM = mediaWiki.parser.getMessageFunction( options );
+ * window.gM = mediaWiki.jqueryMsg.getMessageFunction( options );
* $( 'p#headline' ).html( gM( 'hello-user', username ) );
*
* Like the old gM() function this returns only strings, so it destroys any bindings. If you want to preserve bindings use the
@@ -178,7 +178,7 @@
* the current selector. Bindings to passed-in jquery elements are preserved. Functions become click handlers for [$1 linktext] links.
* e.g.
*
- * $.fn.msg = mediaWiki.parser.getJqueryPlugin( options );
+ * $.fn.msg = mediaWiki.jqueryMsg.getPlugin( options );
* var userlink = $( '<a>' ).click( function () { alert( "hello!!" ) } );
* $( 'p#headline' ).msg( 'hello-user', userlink );
*
@@ -267,7 +267,8 @@
* @return {string|Array} string of '[key]' if message missing, simple string if possible, array of arrays if needs parsing
*/
getAst: function ( key ) {
- var cacheKey = [key, this.settings.onlyCurlyBraceTransform].join( ':' ), wikiText;
+ var wikiText,
+ cacheKey = [key, this.settings.onlyCurlyBraceTransform].join( ':' );
if ( this.astCache[ cacheKey ] === undefined ) {
wikiText = this.settings.messages.get( key );
@@ -290,7 +291,7 @@
* @return {Mixed} abstract syntax tree
*/
wikiTextToAst: function ( input ) {
- var pos, settings = this.settings, concat = Array.prototype.concat,
+ var pos,
regularLiteral, regularLiteralWithoutBar, regularLiteralWithoutSpace, regularLiteralWithSquareBrackets,
doubleQuote, singleQuote, backslash, anyCharacter, asciiAlphabetLiteral,
escapedOrLiteralWithoutSpace, escapedOrLiteralWithoutBar, escapedOrRegularLiteral,
@@ -298,7 +299,9 @@
htmlAttributeEquals, openHtmlStartTag, optionalForwardSlash, openHtmlEndTag, closeHtmlTag,
openExtlink, closeExtlink, wikilinkPage, wikilinkContents, openWikilink, closeWikilink, templateName, pipe, colon,
templateContents, openTemplate, closeTemplate,
- nonWhitespaceExpression, paramExpression, expression, curlyBraceTransformExpression, result;
+ nonWhitespaceExpression, paramExpression, expression, curlyBraceTransformExpression, result,
+ settings = this.settings,
+ concat = Array.prototype.concat;
// Indicates current position in input as we parse through it.
// Shared among all parsing functions below.
@@ -686,10 +689,10 @@
// Subset of allowed HTML markup.
// Most elements and many attributes allowed on the server are not supported yet.
function html() {
- var result = null, parsedOpenTagResult, parsedHtmlContents,
- parsedCloseTagResult, wrappedAttributes, attributes,
- startTagName, endTagName, startOpenTagPos, startCloseTagPos,
- endOpenTagPos, endCloseTagPos;
+ var parsedOpenTagResult, parsedHtmlContents, parsedCloseTagResult,
+ wrappedAttributes, attributes, startTagName, endTagName, startOpenTagPos,
+ startCloseTagPos, endOpenTagPos, endCloseTagPos,
+ result = null;
// Break into three sequence calls. That should allow accurate reconstruction of the original HTML, and requiring an exact tag name match.
// 1. open through closeHtmlTag
@@ -1015,16 +1018,11 @@
page = nodes[0];
url = mw.util.getUrl( page );
- // [[Some Page]] or [[Namespace:Some Page]]
if ( nodes.length === 1 ) {
+ // [[Some Page]] or [[Namespace:Some Page]]
anchor = page;
- }
-
- /*
- * [[Some Page|anchor text]] or
- * [[Namespace:Some Page|anchor]
- */
- else {
+ } else {
+ // [[Some Page|anchor text]] or [[Namespace:Some Page|anchor]]
anchor = nodes[1];
}
@@ -1129,17 +1127,42 @@
* @return {string} selected pluralized form according to current language
*/
plural: function ( nodes ) {
- var forms, formIndex, node, count;
+ var forms, firstChild, firstChildText, explicitPluralFormNumber, formIndex, form, count,
+ explicitPluralForms = {};
+
count = parseFloat( this.language.convertNumber( nodes[0], true ) );
forms = nodes.slice( 1 );
for ( formIndex = 0; formIndex < forms.length; formIndex++ ) {
- node = forms[formIndex];
- if ( node.jquery && node.hasClass( 'mediaWiki_htmlEmitter' ) ) {
- // This is a nested node, already expanded.
- forms[formIndex] = forms[formIndex].html();
+ form = forms[formIndex];
+
+ if ( form.jquery && form.hasClass( 'mediaWiki_htmlEmitter' ) ) {
+ // This is a nested node, may be an explicit plural form like 5=[$2 linktext]
+ firstChild = form.contents().get( 0 );
+ if ( firstChild && firstChild.nodeType === Node.TEXT_NODE ) {
+ firstChildText = firstChild.textContent;
+ if ( /^\d+=/.test( firstChildText ) ) {
+ explicitPluralFormNumber = parseInt( firstChildText.split( /=/ )[0], 10 );
+ // Use the digit part as key and rest of first text node and
+ // rest of child nodes as value.
+ firstChild.textContent = firstChildText.slice( firstChildText.indexOf( '=' ) + 1 );
+ explicitPluralForms[explicitPluralFormNumber] = form;
+ forms[formIndex] = undefined;
+ }
+ }
+ } else if ( /^\d+=/.test( form ) ) {
+ // Simple explicit plural forms like 12=a dozen
+ explicitPluralFormNumber = parseInt( form.split( /=/ )[0], 10 );
+ explicitPluralForms[explicitPluralFormNumber] = form.slice( form.indexOf( '=' ) + 1 );
+ forms[formIndex] = undefined;
}
}
- return forms.length ? this.language.convertPlural( count, forms ) : '';
+
+ // Remove explicit plural forms from the forms. They were set undefined in the above loop.
+ forms = $.map( forms, function ( form ) {
+ return form;
+ } );
+
+ return this.language.convertPlural( count, forms, explicitPluralForms );
},
/**
diff --git a/resources/src/mediawiki/mediawiki.js b/resources/src/mediawiki/mediawiki.js
index e29c734d..ee57c21f 100644
--- a/resources/src/mediawiki/mediawiki.js
+++ b/resources/src/mediawiki/mediawiki.js
@@ -1,7 +1,7 @@
/**
* Base library for MediaWiki.
*
- * Exposed as globally as `mediaWiki` with `mw` as shortcut.
+ * Exposed globally as `mediaWiki` with `mw` as shortcut.
*
* @class mw
* @alternateClassName mediaWiki
@@ -10,8 +10,6 @@
( function ( $ ) {
'use strict';
- /* Private Members */
-
var mw,
hasOwn = Object.prototype.hasOwnProperty,
slice = Array.prototype.slice,
@@ -19,87 +17,104 @@
trackQueue = [];
/**
- * Log a message to window.console, if possible. Useful to force logging of some
- * errors that are otherwise hard to detect (I.e., this logs also in production mode).
- * Gets console references in each invocation, so that delayed debugging tools work
- * fine. No need for optimization here, which would only result in losing logs.
- *
- * @private
- * @method log_
- * @param {string} msg text for the log entry.
- * @param {Error} [e]
- */
- function log( msg, e ) {
- var console = window.console;
- if ( console && console.log ) {
- console.log( msg );
- // If we have an exception object, log it through .error() to trigger
- // proper stacktraces in browsers that support it. There are no (known)
- // browsers that don't support .error(), that do support .log() and
- // have useful exception handling through .log().
- if ( e && console.error ) {
- console.error( String( e ), e );
- }
- }
- }
-
- /* Object constructors */
-
- /**
- * Creates an object that can be read from or written to from prototype functions
- * that allow both single and multiple variables at once.
+ * Create an object that can be read from or written to from methods that allow
+ * interaction both with single and multiple properties at once.
*
* @example
*
- * var addies, wanted, results;
+ * var collection, query, results;
*
* // Create your address book
- * addies = new mw.Map();
+ * collection = new mw.Map();
*
* // This data could be coming from an external source (eg. API/AJAX)
- * addies.set( {
- * 'John Doe' : '10 Wall Street, New York, USA',
- * 'Jane Jackson' : '21 Oxford St, London, UK',
- * 'Dominique van Halen' : 'Kalverstraat 7, Amsterdam, NL'
+ * collection.set( {
+ * 'John Doe': 'john@example.org',
+ * 'Jane Doe': 'jane@example.org',
+ * 'George van Halen': 'gvanhalen@example.org'
* } );
*
- * wanted = ['Dominique van Halen', 'George Johnson', 'Jane Jackson'];
+ * wanted = ['John Doe', 'Jane Doe', 'Daniel Jackson'];
*
* // You can detect missing keys first
- * if ( !addies.exists( wanted ) ) {
- * // One or more are missing (in this case: "George Johnson")
+ * if ( !collection.exists( wanted ) ) {
+ * // One or more are missing (in this case: "Daniel Jackson")
* mw.log( 'One or more names were not found in your address book' );
* }
*
- * // Or just let it give you what it can
- * results = addies.get( wanted, 'Middle of Nowhere, Alaska, US' );
- * mw.log( results['Jane Jackson'] ); // "21 Oxford St, London, UK"
- * mw.log( results['George Johnson'] ); // "Middle of Nowhere, Alaska, US"
+ * // Or just let it give you what it can. Optionally fill in from a default.
+ * results = collection.get( wanted, 'nobody@example.com' );
+ * mw.log( results['Jane Doe'] ); // "jane@example.org"
+ * mw.log( results['Daniel Jackson'] ); // "nobody@example.com"
*
* @class mw.Map
*
* @constructor
- * @param {Object|boolean} [values] Value-bearing object to map, or boolean
- * true to map over the global object. Defaults to an empty object.
+ * @param {Object|boolean} [values] The value-baring object to be mapped. Defaults to an
+ * empty object.
+ * For backwards-compatibility with mw.config, this can also be `true` in which case values
+ * are copied to the Window object as global variables (T72470). Values are copied in
+ * one direction only. Changes to globals are not reflected in the map.
*/
function Map( values ) {
- this.values = values === true ? window : ( values || {} );
- return this;
+ if ( values === true ) {
+ this.values = {};
+
+ // Override #set to also set the global variable
+ this.set = function ( selection, value ) {
+ var s;
+
+ if ( $.isPlainObject( selection ) ) {
+ for ( s in selection ) {
+ setGlobalMapValue( this, s, selection[s] );
+ }
+ return true;
+ }
+ if ( typeof selection === 'string' && arguments.length ) {
+ setGlobalMapValue( this, selection, value );
+ return true;
+ }
+ return false;
+ };
+
+ return;
+ }
+
+ this.values = values || {};
+ }
+
+ /**
+ * Alias property to the global object.
+ *
+ * @private
+ * @static
+ * @param {mw.Map} map
+ * @param {string} key
+ * @param {Mixed} value
+ */
+ function setGlobalMapValue( map, key, value ) {
+ map.values[key] = value;
+ mw.log.deprecate(
+ window,
+ key,
+ value,
+ // Deprecation notice for mw.config globals (T58550, T72470)
+ map === mw.config && 'Use mw.config instead.'
+ );
}
Map.prototype = {
/**
- * Get the value of one or multiple a keys.
+ * Get the value of one or more keys.
*
- * If called with no arguments, all values will be returned.
+ * If called with no arguments, all values are returned.
*
- * @param {string|Array} selection String key or array of keys to get values for.
- * @param {Mixed} [fallback] Value to use in case key(s) do not exist.
- * @return mixed If selection was a string returns the value or null,
- * If selection was an array, returns an object of key/values (value is null if not found),
- * If selection was not passed or invalid, will return the 'values' object member (be careful as
- * objects are always passed by reference in JavaScript!).
- * @return {string|Object|null} Values as a string or object, null if invalid/inexistant.
+ * @param {string|Array} [selection] Key or array of keys to retrieve values for.
+ * @param {Mixed} [fallback=null] Value for keys that don't exist.
+ * @return {Mixed|Object| null} If selection was a string, returns the value,
+ * If selection was an array, returns an object of key/values.
+ * If no selection is passed, the 'values' container is returned. (Beware that,
+ * as is the default in JavaScript, the object is returned by reference.)
*/
get: function ( selection, fallback ) {
var results, i;
@@ -127,16 +142,16 @@
return this.values;
}
- // invalid selection key
+ // Invalid selection key
return null;
},
/**
- * Sets one or multiple key/value pairs.
+ * Set one or more key/value pairs.
*
- * @param {string|Object} selection String key to set value for, or object mapping keys to values.
+ * @param {string|Object} selection Key to set value for, or object mapping keys to values
* @param {Mixed} [value] Value to set (optional, only in use when key is a string)
- * @return {Boolean} This returns true on success, false on failure.
+ * @return {boolean} True on success, false on failure
*/
set: function ( selection, value ) {
var s;
@@ -155,10 +170,10 @@
},
/**
- * Checks if one or multiple keys exist.
+ * Check if one or more keys exist.
*
- * @param {Mixed} selection String key or array of keys to check
- * @return {boolean} Existence of key(s)
+ * @param {Mixed} selection Key or array of keys to check
+ * @return {boolean} True if the key(s) exist
*/
exists: function ( selection ) {
var s;
@@ -230,7 +245,7 @@
* @class mw.Message
*
* @constructor
- * @param {mw.Map} map Message storage
+ * @param {mw.Map} map Message store
* @param {string} key
* @param {Array} [parameters]
*/
@@ -244,24 +259,22 @@
Message.prototype = {
/**
- * Simple message parser, does $N replacement and nothing else.
+ * Get parsed contents of the message.
*
+ * The default parser does simple $N replacements and nothing else.
* This may be overridden to provide a more complex message parser.
- *
- * The primary override is in mediawiki.jqueryMsg.
+ * The primary override is in the mediawiki.jqueryMsg module.
*
* This function will not be called for nonexistent messages.
+ *
+ * @return {string} Parsed message
*/
parser: function () {
- var parameters = this.parameters;
- return this.map.get( this.key ).replace( /\$(\d+)/g, function ( str, match ) {
- var index = parseInt( match, 10 ) - 1;
- return parameters[index] !== undefined ? parameters[index] : '$' + match;
- } );
+ return mw.format.apply( null, [ this.map.get( this.key ) ].concat( this.parameters ) );
},
/**
- * Appends (does not replace) parameters for replacement to the .parameters property.
+ * Add (does not replace) parameters for `N$` placeholder values.
*
* @param {Array} parameters
* @chainable
@@ -275,9 +288,10 @@
},
/**
- * Converts message object to its string form based on the state of format.
+ * Convert message object to its string form based on current format.
*
- * @return {string} Message as a string in the current form or `<key>` if key does not exist.
+ * @return {string} Message as a string in the current form, or `<key>` if key
+ * does not exist.
*/
toString: function () {
var text;
@@ -304,7 +318,7 @@
},
/**
- * Changes format to 'parse' and converts message to string
+ * Change format to 'parse' and convert message to string
*
* If jqueryMsg is loaded, this parses the message text from wikitext
* (where supported) to HTML
@@ -319,7 +333,7 @@
},
/**
- * Changes format to 'plain' and converts message to string
+ * Change format to 'plain' and convert message to string
*
* This substitutes parameters, but otherwise does not change the
* message text.
@@ -332,12 +346,14 @@
},
/**
- * Changes format to 'text' and converts message to string
+ * Change format to 'text' and convert message to string
*
* If jqueryMsg is loaded, {{-transformation is done where supported
* (such as {{plural:}}, {{gender:}}, {{int:}}).
*
- * Otherwise, it is equivalent to plain.
+ * Otherwise, it is equivalent to plain
+ *
+ * @return {string} String form of text message
*/
text: function () {
this.format = 'text';
@@ -345,9 +361,9 @@
},
/**
- * Changes the format to 'escaped' and converts message to string
+ * Change the format to 'escaped' and convert message to string
*
- * This is equivalent to using the 'text' format (see text method), then
+ * This is equivalent to using the 'text' format (see #text), then
* HTML-escaping the output.
*
* @return {string} String form of html escaped message
@@ -358,7 +374,7 @@
},
/**
- * Checks if message exists
+ * Check if a message exists
*
* @see mw.Map#exists
* @return {boolean}
@@ -372,7 +388,6 @@
* @class mw
*/
mw = {
- /* Public Members */
/**
* Get the current time, measured in milliseconds since January 1, 1970 (UTC).
@@ -392,6 +407,24 @@
}() ),
/**
+ * Format a string. Replace $1, $2 ... $N with positional arguments.
+ *
+ * Used by Message#parser().
+ *
+ * @since 1.25
+ * @param {string} fmt Format string
+ * @param {Mixed...} parameters Values for $N replacements
+ * @return {string} Formatted string
+ */
+ format: function ( formatString ) {
+ var parameters = slice.call( arguments, 1 );
+ return formatString.replace( /\$(\d+)/g, function ( str, match ) {
+ var index = parseInt( match, 10 ) - 1;
+ return parameters[index] !== undefined ? parameters[index] : '$' + match;
+ } );
+ },
+
+ /**
* Track an analytic event.
*
* This method provides a generic means for MediaWiki JavaScript code to capture state
@@ -413,7 +446,7 @@
},
/**
- * Register a handler for subset of analytic events, specified by topic
+ * Register a handler for subset of analytic events, specified by topic.
*
* Handlers will be called once for each tracked event, including any events that fired before the
* handler was registered; 'this' is set to a plain object with a 'timeStamp' property indicating
@@ -423,6 +456,8 @@
*
* @param {string} topic Handle events whose name starts with this string prefix
* @param {Function} callback Handler to call for each matching tracked event
+ * @param {string} callback.topic
+ * @param {Object} [callback.data]
*/
trackSubscribe: function ( topic, callback ) {
var seen = 0;
@@ -438,14 +473,14 @@
} );
},
- // Make the Map constructor publicly available.
+ // Expose Map constructor
Map: Map,
- // Make the Message constructor publicly available.
+ // Expose Message constructor
Message: Message,
/**
- * Map of configuration values
+ * Map of configuration values.
*
* Check out [the complete list of configuration values](https://www.mediawiki.org/wiki/Manual:Interface/JavaScript#mw.config)
* on mediawiki.org.
@@ -455,11 +490,14 @@
*
* @property {mw.Map} config
*/
- // Dummy placeholder. Re-assigned in ResourceLoaderStartupModule to an instance of `mw.Map`.
+ // Dummy placeholder later assigned in ResourceLoaderStartUpModule
config: null,
/**
- * Empty object that plugins can be installed in.
+ * Empty object for third-party libraries, for cases where you don't
+ * want to add a new global, or the global is bad and needs containment
+ * or wrapping.
+ *
* @property
*/
libs: {},
@@ -478,12 +516,18 @@
legacy: {},
/**
- * Localization system
+ * Store for messages.
+ *
* @property {mw.Map}
*/
messages: new Map(),
- /* Public Methods */
+ /**
+ * Store for templates associated with a module.
+ *
+ * @property {mw.Map}
+ */
+ templates: new Map(),
/**
* Get a message object.
@@ -492,11 +536,10 @@
*
* @see mw.Message
* @param {string} key Key of message to get
- * @param {Mixed...} parameters Parameters for the $N replacements in messages.
+ * @param {Mixed...} parameters Values for $N replacements
* @return {mw.Message}
*/
message: function ( key ) {
- // Variadic arguments
var parameters = slice.call( arguments, 1 );
return new Message( mw.messages, key, parameters );
},
@@ -508,7 +551,7 @@
*
* @see mw.Message
* @param {string} key Key of message to get
- * @param {Mixed...} parameters Parameters for the $N replacements in messages.
+ * @param {Mixed...} parameters Values for $N replacements
* @return {string}
*/
msg: function () {
@@ -532,7 +575,7 @@
/**
* Write a message the console's warning channel.
* Also logs a stacktrace for easier debugging.
- * Each action is silently ignored if the browser doesn't support it.
+ * Actions not supported by the browser console are silently ignored.
*
* @param {string...} msg Messages to output to console
*/
@@ -553,12 +596,14 @@
* @param {Object} obj Host object of deprecated property
* @param {string} key Name of property to create in `obj`
* @param {Mixed} val The value this property should return when accessed
- * @param {string} [msg] Optional text to include in the deprecation message.
+ * @param {string} [msg] Optional text to include in the deprecation message
*/
log.deprecate = !Object.defineProperty ? function ( obj, key, val ) {
obj[key] = val;
} : function ( obj, key, val, msg ) {
msg = 'Use of "' + key + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' );
+ // Support: IE8
+ // Can throw on Object.defineProperty.
try {
Object.defineProperty( obj, key, {
configurable: true,
@@ -575,7 +620,7 @@
}
} );
} catch ( err ) {
- // IE8 can throw on Object.defineProperty
+ // Fallback to creating a copy of the value to the object.
obj[key] = val;
}
};
@@ -584,42 +629,74 @@
}() ),
/**
- * Client-side module loader which integrates with the MediaWiki ResourceLoader
+ * Client for ResourceLoader server end point.
+ *
+ * This client is in charge of maintaining the module registry and state
+ * machine, initiating network (batch) requests for loading modules, as
+ * well as dependency resolution and execution of source code.
+ *
+ * For more information, refer to
+ * <https://www.mediawiki.org/wiki/ResourceLoader/Features>
+ *
* @class mw.loader
* @singleton
*/
loader: ( function () {
- /* Private Members */
+ /**
+ * Fired via mw.track on various resource loading errors.
+ *
+ * @event resourceloader_exception
+ * @param {Error|Mixed} e The error that was thrown. Almost always an Error
+ * object, but in theory module code could manually throw something else, and that
+ * might also end up here.
+ * @param {string} [module] Name of the module which caused the error. Omitted if the
+ * error is not module-related or the module cannot be easily identified due to
+ * batched handling.
+ * @param {string} source Source of the error. Possible values:
+ *
+ * - style: stylesheet error (only affects old IE where a special style loading method
+ * is used)
+ * - load-callback: exception thrown by user callback
+ * - module-execute: exception thrown by module code
+ * - store-eval: could not evaluate module code cached in localStorage
+ * - store-localstorage-init: localStorage or JSON parse error in mw.loader.store.init
+ * - store-localstorage-json: JSON conversion error in mw.loader.store.set
+ * - store-localstorage-update: localStorage or JSON conversion error in mw.loader.store.update
+ */
/**
- * Mapping of registered modules
+ * Fired via mw.track on resource loading error conditions.
+ *
+ * @event resourceloader_assert
+ * @param {string} source Source of the error. Possible values:
*
- * The jquery module is pre-registered, because it must have already
- * been provided for this object to have been built, and in debug mode
- * jquery would have been provided through a unique loader request,
- * making it impossible to hold back registration of jquery until after
- * mediawiki.
+ * - bug-T59567: failed to cache script due to an Opera function -> string conversion
+ * bug; see <https://phabricator.wikimedia.org/T59567> for details
+ */
+
+ /**
+ * Mapping of registered modules.
*
- * For exact details on support for script, style and messages, look at
- * mw.loader.implement.
+ * See #implement for exact details on support for script, style and messages.
*
* Format:
+ *
* {
* 'moduleName': {
- * // At registry
- * 'version': ############## (unix timestamp),
+ * // From startup mdoule
+ * 'version': ############## (unix timestamp)
* 'dependencies': ['required.foo', 'bar.also', ...], (or) function () {}
- * 'group': 'somegroup', (or) null,
- * 'source': 'local', 'someforeignwiki', (or) null
- * 'state': 'registered', 'loaded', 'loading', 'ready', 'error' or 'missing'
+ * 'group': 'somegroup', (or) null
+ * 'source': 'local', (or) 'anotherwiki'
* 'skip': 'return !!window.Example', (or) null
+ * 'state': 'registered', 'loaded', 'loading', 'ready', 'error', or 'missing'
*
* // Added during implementation
- * 'skipped': true,
- * 'script': ...,
- * 'style': ...,
- * 'messages': { 'key': 'value' },
+ * 'skipped': true
+ * 'script': ...
+ * 'style': ...
+ * 'messages': { 'key': 'value' }
* }
* }
*
@@ -627,32 +704,37 @@
* @private
*/
var registry = {},
- //
// Mapping of sources, keyed by source-id, values are strings.
+ //
// Format:
- // {
- // 'sourceId': 'http://foo.bar/w/load.php'
- // }
+ //
+ // {
+ // 'sourceId': 'http://example.org/w/load.php'
+ // }
//
sources = {},
+
// List of modules which will be loaded as when ready
batch = [],
+
// List of modules to be loaded
queue = [],
+
// List of callback functions waiting for modules to be ready to be called
jobs = [],
+
// Selector cache for the marker element. Use getMarker() to get/use the marker!
$marker = null,
- // Buffer for addEmbeddedCSS.
+
+ // Buffer for #addEmbeddedCSS
cssBuffer = '',
- // Callbacks for addEmbeddedCSS.
- cssCallbacks = $.Callbacks();
- /* Private methods */
+ // Callbacks for #addEmbeddedCSS
+ cssCallbacks = $.Callbacks();
function getMarker() {
- // Cached
if ( !$marker ) {
+ // Cache
$marker = $( 'meta[name="ResourceLoaderDynamicStyles"]' );
if ( !$marker.length ) {
mw.log( 'No <meta name="ResourceLoaderDynamicStyles"> found, inserting dynamically' );
@@ -663,60 +745,35 @@
}
/**
- * Create a new style tag and add it to the DOM.
+ * Create a new style element and add it to the DOM.
*
* @private
* @param {string} text CSS text
- * @param {HTMLElement|jQuery} [nextnode=document.head] The element where the style tag should be
- * inserted before. Otherwise it will be appended to `<head>`.
- * @return {HTMLElement} Reference to the created `<style>` element.
+ * @param {HTMLElement|jQuery} [nextnode=document.head] The element where the style tag
+ * should be inserted before
+ * @return {HTMLElement} Reference to the created style element
*/
function newStyleTag( text, nextnode ) {
var s = document.createElement( 'style' );
- // Insert into document before setting cssText (bug 33305)
+ // Support: IE
+ // Must attach to document before setting cssText (bug 33305)
if ( nextnode ) {
- // Must be inserted with native insertBefore, not $.fn.before.
- // When using jQuery to insert it, like $nextnode.before( s ),
- // then IE6 will throw "Access is denied" when trying to append
- // to .cssText later. Some kind of weird security measure.
- // http://stackoverflow.com/q/12586482/319266
- // Works: jsfiddle.net/zJzMy/1
- // Fails: jsfiddle.net/uJTQz
- // Works again: http://jsfiddle.net/Azr4w/ (diff: the next 3 lines)
- if ( nextnode.jquery ) {
- nextnode = nextnode.get( 0 );
- }
- nextnode.parentNode.insertBefore( s, nextnode );
+ $( nextnode ).before( s );
} else {
document.getElementsByTagName( 'head' )[0].appendChild( s );
}
if ( s.styleSheet ) {
- // IE
+ // Support: IE6-10
+ // Old IE ignores appended text nodes, access stylesheet directly.
s.styleSheet.cssText = text;
} else {
- // Other browsers.
- // (Safari sometimes borks on non-string values,
- // play safe by casting to a string, just in case.)
- s.appendChild( document.createTextNode( String( text ) ) );
+ // Standard behaviour
+ s.appendChild( document.createTextNode( text ) );
}
return s;
}
/**
- * Checks whether it is safe to add this css to a stylesheet.
- *
- * @private
- * @param {string} cssText
- * @return {boolean} False if a new one must be created.
- */
- function canExpandStylesheetWith( cssText ) {
- // Makes sure that cssText containing `@import`
- // rules will end up in a new stylesheet (as those only work when
- // placed at the start of a stylesheet; bug 35562).
- return cssText.indexOf( '@import' ) === -1;
- }
-
- /**
* Add a bit of CSS text to the current browser page.
*
* The CSS will be appended to an existing ResourceLoader-created `<style>` tag
@@ -736,16 +793,18 @@
// Yield once before inserting the <style> tag. There are likely
// more calls coming up which we can combine this way.
// Appending a stylesheet and waiting for the browser to repaint
- // is fairly expensive, this reduces it (bug 45810)
+ // is fairly expensive, this reduces that (bug 45810)
if ( cssText ) {
- // Be careful not to extend the buffer with css that needs a new stylesheet
- if ( !cssBuffer || canExpandStylesheetWith( cssText ) ) {
+ // Be careful not to extend the buffer with css that needs a new stylesheet.
+ // cssText containing `@import` rules needs to go at the start of a buffer,
+ // since those only work when placed at the start of a stylesheet; bug 35562.
+ if ( !cssBuffer || cssText.slice( 0, '@import'.length ) !== '@import' ) {
// Linebreak for somewhat distinguishable sections
// (the rl-cachekey comment separating each)
cssBuffer += '\n' + cssText;
// TODO: Use requestAnimationFrame in the future which will
// perform even better by not injecting styles while the browser
- // is paiting.
+ // is painting.
setTimeout( function () {
// Can't pass addEmbeddedCSS to setTimeout directly because Firefox
// (below version 13) has the non-standard behaviour of passing a
@@ -760,8 +819,9 @@
} else if ( cssBuffer ) {
cssText = cssBuffer;
cssBuffer = '';
+
} else {
- // This is a delayed call, but buffer is already cleared by
+ // This is a delayed call, but buffer was already cleared by
// another delayed call.
return;
}
@@ -774,21 +834,22 @@
if ( 'documentMode' in document && document.documentMode <= 9 ) {
$style = getMarker().prev();
- // Verify that the the element before Marker actually is a
+ // Verify that the element before the marker actually is a
// <style> tag and one that came from ResourceLoader
// (not some other style tag or even a `<meta>` or `<script>`).
if ( $style.data( 'ResourceLoaderDynamicStyleTag' ) === true ) {
// There's already a dynamic <style> tag present and
- // canExpandStylesheetWith() gave a green light to append more to it.
+ // we are able to append more to it.
styleEl = $style.get( 0 );
+ // Support: IE6-10
if ( styleEl.styleSheet ) {
try {
- styleEl.styleSheet.cssText += cssText; // IE
+ styleEl.styleSheet.cssText += cssText;
} catch ( e ) {
- log( 'Stylesheet error', e );
+ mw.track( 'resourceloader.exception', { exception: e, source: 'stylesheet' } );
}
} else {
- styleEl.appendChild( document.createTextNode( String( cssText ) ) );
+ styleEl.appendChild( document.createTextNode( cssText ) );
}
cssCallbacks.fire().empty();
return;
@@ -801,39 +862,57 @@
}
/**
- * Generates an ISO8601 "basic" string from a UNIX timestamp
+ * Zero-pad three numbers.
+ *
+ * @private
+ * @param {number} a
+ * @param {number} b
+ * @param {number} c
+ * @return {string}
+ */
+ function pad( a, b, c ) {
+ return (
+ ( a < 10 ? '0' : '' ) + a +
+ ( b < 10 ? '0' : '' ) + b +
+ ( c < 10 ? '0' : '' ) + c
+ );
+ }
+
+ /**
+ * Convert UNIX timestamp to ISO8601 format.
+ *
* @private
+ * @param {number} timestamp UNIX timestamp
*/
function formatVersionNumber( timestamp ) {
var d = new Date();
- function pad( a, b, c ) {
- return [a < 10 ? '0' + a : a, b < 10 ? '0' + b : b, c < 10 ? '0' + c : c].join( '' );
- }
d.setTime( timestamp * 1000 );
return [
- pad( d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate() ), 'T',
- pad( d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds() ), 'Z'
+ pad( d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate() ),
+ 'T',
+ pad( d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds() ),
+ 'Z'
].join( '' );
}
/**
- * Resolves dependencies and detects circular references.
+ * Resolve dependencies and detect circular references.
*
* @private
* @param {string} module Name of the top-level module whose dependencies shall be
- * resolved and sorted.
+ * resolved and sorted.
* @param {Array} resolved Returns a topological sort of the given module and its
- * dependencies, such that later modules depend on earlier modules. The array
- * contains the module names. If the array contains already some module names,
- * this function appends its result to the pre-existing array.
+ * dependencies, such that later modules depend on earlier modules. The array
+ * contains the module names. If the array contains already some module names,
+ * this function appends its result to the pre-existing array.
* @param {Object} [unresolved] Hash used to track the current dependency
- * chain; used to report loops in the dependency graph.
+ * chain; used to report loops in the dependency graph.
* @throws {Error} If any unregistered module or a dependency loop is encountered
*/
function sortDependencies( module, resolved, unresolved ) {
var n, deps, len, skip;
- if ( registry[module] === undefined ) {
+ if ( !hasOwn.call( registry, module ) ) {
throw new Error( 'Unknown dependency: ' + module );
}
@@ -859,10 +938,10 @@
}
}
if ( $.inArray( module, resolved ) !== -1 ) {
- // Module already resolved; nothing to do.
+ // Module already resolved; nothing to do
return;
}
- // unresolved is optional, supply it if not passed in
+ // Create unresolved if not passed in
if ( !unresolved ) {
unresolved = {};
}
@@ -888,81 +967,37 @@
}
/**
- * Gets a list of module names that a module depends on in their proper dependency
+ * Get a list of module names that a module depends on in their proper dependency
* order.
*
* @private
- * @param {string} module Module name or array of string module names
- * @return {Array} list of dependencies, including 'module'.
- * @throws {Error} If circular reference is detected
+ * @param {string[]} module Array of string module names
+ * @return {Array} List of dependencies, including 'module'.
*/
- function resolve( module ) {
- var m, resolved;
-
- // Allow calling with an array of module names
- if ( $.isArray( module ) ) {
- resolved = [];
- for ( m = 0; m < module.length; m += 1 ) {
- sortDependencies( module[m], resolved );
- }
- return resolved;
- }
-
- if ( typeof module === 'string' ) {
- resolved = [];
+ function resolve( modules ) {
+ var resolved = [];
+ $.each( modules, function ( idx, module ) {
sortDependencies( module, resolved );
- return resolved;
- }
-
- throw new Error( 'Invalid module argument: ' + module );
+ } );
+ return resolved;
}
/**
- * Narrows a list of module names down to those matching a specific
- * state (see comment on top of this scope for a list of valid states).
- * One can also filter for 'unregistered', which will return the
- * modules names that don't have a registry entry.
+ * Determine whether all dependencies are in state 'ready', which means we may
+ * execute the module or job now.
*
* @private
- * @param {string|string[]} states Module states to filter by
- * @param {Array} [modules] List of module names to filter (optional, by default the entire
- * registry is used)
- * @return {Array} List of filtered module names
+ * @param {Array} module Names of modules to be checked
+ * @return {boolean} True if all modules are in state 'ready', false otherwise
*/
- function filter( states, modules ) {
- var list, module, s, m;
-
- // Allow states to be given as a string
- if ( typeof states === 'string' ) {
- states = [states];
- }
- // If called without a list of modules, build and use a list of all modules
- list = [];
- if ( modules === undefined ) {
- modules = [];
- for ( module in registry ) {
- modules[modules.length] = module;
- }
- }
- // Build a list of modules which are in one of the specified states
- for ( s = 0; s < states.length; s += 1 ) {
- for ( m = 0; m < modules.length; m += 1 ) {
- if ( registry[modules[m]] === undefined ) {
- // Module does not exist
- if ( states[s] === 'unregistered' ) {
- // OK, undefined
- list[list.length] = modules[m];
- }
- } else {
- // Module exists, check state
- if ( registry[modules[m]].state === states[s] ) {
- // OK, correct state
- list[list.length] = modules[m];
- }
- }
+ function allReady( modules ) {
+ var i;
+ for ( i = 0; i < modules.length; i++ ) {
+ if ( mw.loader.getState( modules[i] ) !== 'ready' ) {
+ return false;
}
}
- return list;
+ return true;
}
/**
@@ -970,18 +1005,27 @@
* execute the module or job now.
*
* @private
- * @param {Array} dependencies Dependencies (module names) to be checked.
- * @return {boolean} True if all dependencies are in state 'ready', false otherwise
+ * @param {Array} modules Names of modules to be checked
+ * @return {boolean} True if no modules are in state 'error' or 'missing', false otherwise
*/
- function allReady( dependencies ) {
- return filter( 'ready', dependencies ).length === dependencies.length;
+ function anyFailed( modules ) {
+ var i, state;
+ for ( i = 0; i < modules.length; i++ ) {
+ state = mw.loader.getState( modules[i] );
+ if ( state === 'error' || state === 'missing' ) {
+ return true;
+ }
+ }
+ return false;
}
/**
- * A module has entered state 'ready', 'error', or 'missing'. Automatically update pending jobs
- * and modules that depend upon this module. if the given module failed, propagate the 'error'
- * state up the dependency tree; otherwise, execute all jobs/modules that now have all their
- * dependencies satisfied. On jobs depending on a failed module, run the error callback, if any.
+ * A module has entered state 'ready', 'error', or 'missing'. Automatically update
+ * pending jobs and modules that depend upon this module. If the given module failed,
+ * propagate the 'error' state up the dependency tree. Otherwise, go ahead an execute
+ * all jobs/modules now having their dependencies satisfied.
+ *
+ * Jobs that depend on a failed module, will have their error callback ran (if any).
*
* @private
* @param {string} module Name of module that entered one of the states 'ready', 'error', or 'missing'.
@@ -989,16 +1033,15 @@
function handlePending( module ) {
var j, job, hasErrors, m, stateChange;
- // Modules.
- if ( $.inArray( registry[module].state, ['error', 'missing'] ) !== -1 ) {
+ if ( registry[module].state === 'error' || registry[module].state === 'missing' ) {
// If the current module failed, mark all dependent modules also as failed.
// Iterate until steady-state to propagate the error state upwards in the
// dependency tree.
do {
stateChange = false;
for ( m in registry ) {
- if ( $.inArray( registry[m].state, ['error', 'missing'] ) === -1 ) {
- if ( filter( ['error', 'missing'], registry[m].dependencies ).length > 0 ) {
+ if ( registry[m].state !== 'error' && registry[m].state !== 'missing' ) {
+ if ( anyFailed( registry[m].dependencies ) ) {
registry[m].state = 'error';
stateChange = true;
}
@@ -1009,7 +1052,7 @@
// Execute all jobs whose dependencies are either all satisfied or contain at least one failed module.
for ( j = 0; j < jobs.length; j += 1 ) {
- hasErrors = filter( ['error', 'missing'], jobs[j].dependencies ).length > 0;
+ hasErrors = anyFailed( jobs[j].dependencies );
if ( hasErrors || allReady( jobs[j].dependencies ) ) {
// All dependencies satisfied, or some have errors
job = jobs[j];
@@ -1028,7 +1071,7 @@
} catch ( e ) {
// A user-defined callback raised an exception.
// Swallow it to protect our state machine!
- log( 'Exception thrown by user callback', e );
+ mw.track( 'resourceloader.exception', { exception: e, module: module, source: 'load-callback' } );
}
}
}
@@ -1091,7 +1134,7 @@
var key, value, media, i, urls, cssHandle, checkCssHandles,
cssHandlesRegistered = false;
- if ( registry[module] === undefined ) {
+ if ( !hasOwn.call( registry, module ) ) {
throw new Error( 'Module has not been registered yet: ' + module );
} else if ( registry[module].state === 'registered' ) {
throw new Error( 'Module has not been requested from the server yet: ' + module );
@@ -1108,7 +1151,8 @@
*/
function addLink( media, url ) {
var el = document.createElement( 'link' );
- // For IE: Insert in document *before* setting href
+ // Support: IE
+ // Insert in document *before* setting href
getMarker().before( el );
el.rel = 'stylesheet';
if ( media && media !== 'all' ) {
@@ -1153,8 +1197,8 @@
} catch ( e ) {
// This needs to NOT use mw.log because these errors are common in production mode
// and not in debug mode, such as when a symbol that should be global isn't exported
- log( 'Exception thrown by ' + module, e );
registry[module].state = 'error';
+ mw.track( 'resourceloader.exception', { exception: e, module: module, source: 'module-execute' } );
handlePending( module );
}
}
@@ -1170,6 +1214,11 @@
mw.messages.set( registry[module].messages );
}
+ // Initialise templates
+ if ( registry[module].templates ) {
+ mw.templates.set( module, registry[module].templates );
+ }
+
if ( $.isReady || registry[module].async ) {
// Make sure we don't run the scripts until all (potentially asynchronous)
// stylesheet insertions have completed.
@@ -1187,7 +1236,7 @@
var check = checkCssHandles;
pending++;
return function () {
- if (check) {
+ if ( check ) {
pending--;
check();
check = undefined; // Revoke
@@ -1271,8 +1320,6 @@
* Ignored (and defaulted to `true`) if the document-ready event has already occurred.
*/
function request( dependencies, ready, error, async ) {
- var n;
-
// Allow calling by single module name
if ( typeof dependencies === 'string' ) {
dependencies = [dependencies];
@@ -1281,33 +1328,33 @@
// Add ready and error callbacks if they were given
if ( ready !== undefined || error !== undefined ) {
jobs[jobs.length] = {
- 'dependencies': filter(
- ['registered', 'loading', 'loaded'],
- dependencies
- ),
- 'ready': ready,
- 'error': error
+ dependencies: $.grep( dependencies, function ( module ) {
+ var state = mw.loader.getState( module );
+ return state === 'registered' || state === 'loaded' || state === 'loading';
+ } ),
+ ready: ready,
+ error: error
};
}
- // Queue up any dependencies that are registered
- dependencies = filter( ['registered'], dependencies );
- for ( n = 0; n < dependencies.length; n += 1 ) {
- if ( $.inArray( dependencies[n], queue ) === -1 ) {
- queue[queue.length] = dependencies[n];
+ $.each( dependencies, function ( idx, module ) {
+ var state = mw.loader.getState( module );
+ if ( state === 'registered' && $.inArray( module, queue ) === -1 ) {
+ queue.push( module );
if ( async ) {
- // Mark this module as async in the registry
- registry[dependencies[n]].async = true;
+ registry[module].async = true;
}
}
- }
+ } );
- // Work the queue
mw.loader.work();
}
function sortQuery( o ) {
- var sorted = {}, key, a = [];
+ var key,
+ sorted = {},
+ a = [];
+
for ( key in o ) {
if ( hasOwn.call( o, key ) ) {
a.push( key );
@@ -1326,7 +1373,9 @@
* @private
*/
function buildModulesString( moduleMap ) {
- var arr = [], p, prefix;
+ var p, prefix,
+ arr = [];
+
for ( prefix in moduleMap ) {
p = prefix === '' ? '' : prefix + '.';
arr.push( p + moduleMap[prefix].join( ',' ) );
@@ -1350,10 +1399,33 @@
currReqBase
);
request = sortQuery( request );
- // Append &* to avoid triggering the IE6 extension check
+ // Support: IE6
+ // Append &* to satisfy load.php's WebRequest::checkUrlExtension test. This script
+ // isn't actually used in IE6, but MediaWiki enforces it in general.
addScript( sourceLoadScript + '?' + $.param( request ) + '&*', null, async );
}
+ /**
+ * Resolve indexed dependencies.
+ *
+ * ResourceLoader uses an optimization to save space which replaces module names in
+ * dependency lists with the index of that module within the array of module
+ * registration data if it exists. The benefit is a significant reduction in the data
+ * size of the startup module. This function changes those dependency lists back to
+ * arrays of strings.
+ *
+ * @param {Array} modules Modules array
+ */
+ function resolveIndexedDependencies( modules ) {
+ $.each( modules, function ( idx, module ) {
+ if ( module[2] ) {
+ module[2] = $.map( module[2], function ( dep ) {
+ return typeof dep === 'number' ? modules[dep][0] : dep;
+ } );
+ }
+ } );
+ }
+
/* Public Members */
return {
/**
@@ -1389,12 +1461,12 @@
};
// Split module batch by source and by group.
splits = {};
- maxQueryLength = mw.config.get( 'wgResourceLoaderMaxQueryLength', -1 );
+ maxQueryLength = mw.config.get( 'wgResourceLoaderMaxQueryLength', 2000 );
// Appends a list of modules from the queue to the batch
for ( q = 0; q < queue.length; q += 1 ) {
// Only request modules which are registered
- if ( registry[queue[q]] !== undefined && registry[queue[q]].state === 'registered' ) {
+ if ( hasOwn.call( registry, queue[q] ) && registry[queue[q]].state === 'registered' ) {
// Prevent duplicate entries
if ( $.inArray( queue[q], batch ) === -1 ) {
batch[batch.length] = queue[q];
@@ -1433,7 +1505,7 @@
// repopulate these modules to the cache.
// This means that at most one module will be useless (the one that had
// the error) instead of all of them.
- log( 'Error while evaluating data from mw.loader.store', err );
+ mw.track( 'resourceloader.exception', { exception: err, source: 'store-eval' } );
origBatch = $.grep( origBatch, function ( module ) {
return registry[module].state === 'loading';
} );
@@ -1457,10 +1529,10 @@
for ( b = 0; b < batch.length; b += 1 ) {
bSource = registry[batch[b]].source;
bGroup = registry[batch[b]].group;
- if ( splits[bSource] === undefined ) {
+ if ( !hasOwn.call( splits, bSource ) ) {
splits[bSource] = {};
}
- if ( splits[bSource][bGroup] === undefined ) {
+ if ( !hasOwn.call( splits[bSource], bGroup ) ) {
splits[bSource][bGroup] = [];
}
bSourceGroup = splits[bSource][bGroup];
@@ -1513,7 +1585,7 @@
prefix = modules[i].substr( 0, lastDotIndex );
suffix = modules[i].slice( lastDotIndex + 1 );
- bytesAdded = moduleMap[prefix] !== undefined
+ bytesAdded = hasOwn.call( moduleMap, prefix )
? suffix.length + 3 // '%2C'.length == 3
: modules[i].length + 3; // '%7C'.length == 3
@@ -1526,8 +1598,9 @@
moduleMap = {};
async = true;
l = currReqBaseLength + 9;
+ mw.track( 'resourceloader.splitRequest', { maxQueryLength: maxQueryLength } );
}
- if ( moduleMap[prefix] === undefined ) {
+ if ( !hasOwn.call( moduleMap, prefix ) ) {
moduleMap[prefix] = [];
}
moduleMap[prefix].push( suffix );
@@ -1569,7 +1642,7 @@
return true;
}
- if ( sources[id] !== undefined ) {
+ if ( hasOwn.call( sources, id ) ) {
throw new Error( 'source already registered: ' + id );
}
@@ -1586,7 +1659,12 @@
* Register a module, letting the system know about it and its
* properties. Startup modules contain calls to this function.
*
- * @param {string} module Module name
+ * When using multiple module registration by passing an array, dependencies that
+ * are specified as references to modules within the array will be resolved before
+ * the modules are registered.
+ *
+ * @param {string|Array} module Module name or array of arrays, each containing
+ * a list of arguments compatible with this method
* @param {number} version Module version number as a timestamp (falls backs to 0)
* @param {string|Array|Function} dependencies One string or array of strings of module
* names on which this module depends, or a function that returns that array.
@@ -1595,16 +1673,17 @@
* @param {string} [skip=null] Script body of the skip function
*/
register: function ( module, version, dependencies, group, source, skip ) {
- var m;
+ var i, len;
// Allow multiple registration
if ( typeof module === 'object' ) {
- for ( m = 0; m < module.length; m += 1 ) {
+ resolveIndexedDependencies( module );
+ for ( i = 0, len = module.length; i < len; i++ ) {
// module is an array of module names
- if ( typeof module[m] === 'string' ) {
- mw.loader.register( module[m] );
+ if ( typeof module[i] === 'string' ) {
+ mw.loader.register( module[i] );
// module is an array of arrays
- } else if ( typeof module[m] === 'object' ) {
- mw.loader.register.apply( mw.loader, module[m] );
+ } else if ( typeof module[i] === 'object' ) {
+ mw.loader.register.apply( mw.loader, module[i] );
}
}
return;
@@ -1613,7 +1692,7 @@
if ( typeof module !== 'string' ) {
throw new Error( 'module must be a string, not a ' + typeof module );
}
- if ( registry[module] !== undefined ) {
+ if ( hasOwn.call( registry, module ) ) {
throw new Error( 'module already registered: ' + module );
}
// List the module as registered
@@ -1646,7 +1725,7 @@
* @param {string} module Name of module
* @param {Function|Array} script Function with module code or Array of URLs to
* be used as the src attribute of a new `<script>` tag.
- * @param {Object} style Should follow one of the following patterns:
+ * @param {Object} [style] Should follow one of the following patterns:
*
* { "css": [css, ..] }
* { "url": { <media>: [url, ..] } }
@@ -1657,36 +1736,41 @@
* { <media>: [url, ..] }
*
* The reason css strings are not concatenated anymore is bug 31676. We now check
- * whether it's safe to extend the stylesheet (see #canExpandStylesheetWith).
+ * whether it's safe to extend the stylesheet.
*
- * @param {Object} msgs List of key/value pairs to be added to mw#messages.
+ * @param {Object} [msgs] List of key/value pairs to be added to mw#messages.
+ * @param {Object} [templates] List of key/value pairs to be added to mw#templates.
*/
- implement: function ( module, script, style, msgs ) {
+ implement: function ( module, script, style, msgs, templates ) {
// Validate input
if ( typeof module !== 'string' ) {
- throw new Error( 'module must be a string, not a ' + typeof module );
+ throw new Error( 'module must be of type string, not ' + typeof module );
}
- if ( !$.isFunction( script ) && !$.isArray( script ) ) {
- throw new Error( 'script must be a function or an array, not a ' + typeof script );
+ if ( script && !$.isFunction( script ) && !$.isArray( script ) ) {
+ throw new Error( 'script must be of type function or array, not ' + typeof script );
}
- if ( !$.isPlainObject( style ) ) {
- throw new Error( 'style must be an object, not a ' + typeof style );
+ if ( style && !$.isPlainObject( style ) ) {
+ throw new Error( 'style must be of type object, not ' + typeof style );
}
- if ( !$.isPlainObject( msgs ) ) {
- throw new Error( 'msgs must be an object, not a ' + typeof msgs );
+ if ( msgs && !$.isPlainObject( msgs ) ) {
+ throw new Error( 'msgs must be of type object, not a ' + typeof msgs );
+ }
+ if ( templates && !$.isPlainObject( templates ) ) {
+ throw new Error( 'templates must be of type object, not a ' + typeof templates );
}
// Automatically register module
- if ( registry[module] === undefined ) {
+ if ( !hasOwn.call( registry, module ) ) {
mw.loader.register( module );
}
// Check for duplicate implementation
- if ( registry[module] !== undefined && registry[module].script !== undefined ) {
+ if ( hasOwn.call( registry, module ) && registry[module].script !== undefined ) {
throw new Error( 'module already implemented: ' + module );
}
// Attach components
- registry[module].script = script;
- registry[module].style = style;
- registry[module].messages = msgs;
+ registry[module].script = script || [];
+ registry[module].style = style || {};
+ registry[module].messages = msgs || {};
+ registry[module].templates = templates || {};
// The module may already have been marked as erroneous
if ( $.inArray( registry[module].state, ['error', 'missing'] ) === -1 ) {
registry[module].state = 'loaded';
@@ -1710,6 +1794,7 @@
* @param {Function} [ready] Callback to execute when all dependencies are ready
* @param {Function} [error] Callback to execute if one or more dependencies failed
* @return {jQuery.Promise}
+ * @since 1.23 this returns a promise
*/
using: function ( dependencies, ready, error ) {
var deferred = $.Deferred();
@@ -1734,7 +1819,7 @@
if ( allReady( dependencies ) ) {
// Run ready immediately
deferred.resolve();
- } else if ( filter( ['error', 'missing'], dependencies ).length ) {
+ } else if ( anyFailed( dependencies ) ) {
// Execute error immediately if any dependencies have errors
deferred.reject(
new Error( 'One or more dependencies failed to load' ),
@@ -1761,7 +1846,7 @@
* Defaults to `true` if loading a URL, `false` otherwise.
*/
load: function ( modules, type, async ) {
- var filtered, m, module, l;
+ var filtered, l;
// Validate input
if ( typeof modules !== 'object' && typeof modules !== 'string' ) {
@@ -1769,16 +1854,16 @@
}
// Allow calling with an external url or single dependency as a string
if ( typeof modules === 'string' ) {
- // Support adding arbitrary external scripts
if ( /^(https?:)?\/\//.test( modules ) ) {
if ( async === undefined ) {
// Assume async for bug 34542
async = true;
}
if ( type === 'text/css' ) {
- // IE7-8 throws security warnings when inserting a <link> tag
- // with a protocol-relative URL set though attributes (instead of
- // properties) - when on HTTPS. See also bug 41331.
+ // Support: IE 7-8
+ // Use properties instead of attributes as IE throws security
+ // warnings when inserting a <link> tag with a protocol-relative
+ // URL set though attributes - when on HTTPS. See bug 41331.
l = document.createElement( 'link' );
l.rel = 'stylesheet';
l.href = modules;
@@ -1801,26 +1886,18 @@
// Undefined modules are acceptable here in load(), because load() takes
// an array of unrelated modules, whereas the modules passed to
// using() are related and must all be loaded.
- for ( filtered = [], m = 0; m < modules.length; m += 1 ) {
- module = registry[modules[m]];
- if ( module !== undefined ) {
- if ( $.inArray( module.state, ['error', 'missing'] ) === -1 ) {
- filtered[filtered.length] = modules[m];
- }
- }
- }
+ filtered = $.grep( modules, function ( module ) {
+ var state = mw.loader.getState( module );
+ return state !== null && state !== 'error' && state !== 'missing';
+ } );
if ( filtered.length === 0 ) {
return;
}
// Resolve entire dependency map
filtered = resolve( filtered );
- // If all modules are ready, nothing to be done
- if ( allReady( filtered ) ) {
- return;
- }
- // If any modules have errors: also quit.
- if ( filter( ['error', 'missing'], filtered ).length ) {
+ // If all modules are ready, or if any modules have errors, nothing to be done.
+ if ( allReady( filtered ) || anyFailed( filtered ) ) {
return;
}
// Since some modules are not yet ready, queue up a request.
@@ -1842,7 +1919,7 @@
}
return;
}
- if ( registry[module] === undefined ) {
+ if ( !hasOwn.call( registry, module ) ) {
mw.loader.register( module );
}
if ( $.inArray( state, ['ready', 'error', 'missing'] ) !== -1
@@ -1859,27 +1936,29 @@
/**
* Get the version of a module.
*
- * @param {string} module Name of module to get version for
+ * @param {string} module Name of module
* @return {string|null} The version, or null if the module (or its version) is not
* in the registry.
*/
getVersion: function ( module ) {
- if ( registry[module] !== undefined && registry[module].version !== undefined ) {
- return formatVersionNumber( registry[module].version );
+ if ( !hasOwn.call( registry, module ) || registry[module].version === undefined ) {
+ return null;
}
- return null;
+ return formatVersionNumber( registry[module].version );
},
/**
* Get the state of a module.
*
- * @param {string} module Name of module to get state for
+ * @param {string} module Name of module
+ * @return {string|null} The state, or null if the module (or its state) is not
+ * in the registry.
*/
getState: function ( module ) {
- if ( registry[module] !== undefined && registry[module].state !== undefined ) {
- return registry[module].state;
+ if ( !hasOwn.call( registry, module ) || registry[module].state === undefined ) {
+ return null;
}
- return null;
+ return registry[module].state;
},
/**
@@ -1944,7 +2023,7 @@
},
/**
- * Get a string key on which to vary the module cache.
+ * Get a key on which to vary the module cache.
* @return {string} String of concatenated vary conditions.
*/
getVary: function () {
@@ -1956,13 +2035,13 @@
},
/**
- * Get a string key for a specific module. The key format is '[name]@[version]'.
+ * Get a key for a specific module. The key format is '[name]@[version]'.
*
* @param {string} module Module name
* @return {string|null} Module key or null if module does not exist
*/
getModuleKey: function ( module ) {
- return typeof registry[module] === 'object' ?
+ return hasOwn.call( registry, module ) ?
( module + '@' + registry[module].version ) : null;
},
@@ -1985,8 +2064,15 @@
return;
}
- if ( !mw.config.get( 'wgResourceLoaderStorageEnabled' ) || mw.config.get( 'debug' ) ) {
- // Disabled by configuration, or because debug mode is set
+ if ( !mw.config.get( 'wgResourceLoaderStorageEnabled' ) ) {
+ // Disabled by configuration.
+ // Clear any previous store to free up space. (T66721)
+ mw.loader.store.clear();
+ mw.loader.store.enabled = false;
+ return;
+ }
+ if ( mw.config.get( 'debug' ) ) {
+ // Disable module store in debug mode
mw.loader.store.enabled = false;
return;
}
@@ -2001,7 +2087,7 @@
return;
}
} catch ( e ) {
- log( 'Storage error', e );
+ mw.track( 'resourceloader.exception', { exception: e, source: 'store-localstorage-init' } );
}
if ( raw === undefined ) {
@@ -2057,7 +2143,8 @@
// Unversioned, private, or site-/user-specific
( !descriptor.version || $.inArray( descriptor.group, [ 'private', 'user', 'site' ] ) !== -1 ) ||
// Partial descriptor
- $.inArray( undefined, [ descriptor.script, descriptor.style, descriptor.messages ] ) !== -1
+ $.inArray( undefined, [ descriptor.script, descriptor.style,
+ descriptor.messages, descriptor.templates ] ) !== -1
) {
// Decline to store
return false;
@@ -2070,16 +2157,17 @@
String( descriptor.script ) :
JSON.stringify( descriptor.script ),
JSON.stringify( descriptor.style ),
- JSON.stringify( descriptor.messages )
+ JSON.stringify( descriptor.messages ),
+ JSON.stringify( descriptor.templates )
];
- // Attempted workaround for a possible Opera bug (bug 57567).
+ // Attempted workaround for a possible Opera bug (bug T59567).
// This regex should never match under sane conditions.
if ( /^\s*\(/.test( args[1] ) ) {
args[1] = 'function' + args[1];
- log( 'Detected malformed function stringification (bug 57567)' );
+ mw.track( 'resourceloader.assert', { source: 'bug-T59567' } );
}
} catch ( e ) {
- log( 'Storage error', e );
+ mw.track( 'resourceloader.exception', { exception: e, source: 'store-localstorage-json' } );
return;
}
@@ -2151,7 +2239,7 @@
data = JSON.stringify( mw.loader.store );
localStorage.setItem( key, data );
} catch ( e ) {
- log( 'Storage error', e );
+ mw.track( 'resourceloader.exception', { exception: e, source: 'store-localstorage-update' } );
}
}
@@ -2223,8 +2311,8 @@
* - null or undefined: The short closing form is used, e.g. `<br/>`.
* - this.Raw: The value attribute is included without escaping.
* - this.Cdata: The value attribute is included, and an exception is
- * thrown if it contains an illegal ETAGO delimiter.
- * See <http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.3.2>.
+ * thrown if it contains an illegal ETAGO delimiter.
+ * See <http://www.w3.org/TR/1999/REC-html401-19991224/appendix/notes.html#h-B.3.2>.
* @return {string} HTML
*/
element: function ( name, attrs, contents ) {
@@ -2387,13 +2475,49 @@
// @deprecated since 1.23 Use $ or jQuery instead
mw.log.deprecate( window, '$j', $, 'Use $ or jQuery instead.' );
- // Attach to window and globally alias
- window.mw = window.mediaWiki = mw;
+ /**
+ * Log a message to window.console, if possible.
+ *
+ * Useful to force logging of some errors that are otherwise hard to detect (i.e., this logs
+ * also in production mode). Gets console references in each invocation instead of caching the
+ * reference, so that debugging tools loaded later are supported (e.g. Firebug Lite in IE).
+ *
+ * @private
+ * @method log_
+ * @param {string} topic Stream name passed by mw.track
+ * @param {Object} data Data passed by mw.track
+ * @param {Error} [data.exception]
+ * @param {string} data.source Error source
+ * @param {string} [data.module] Name of module which caused the error
+ */
+ function log( topic, data ) {
+ var msg,
+ e = data.exception,
+ source = data.source,
+ module = data.module,
+ console = window.console;
- // Auto-register from pre-loaded startup scripts
- if ( $.isFunction( window.startUp ) ) {
- window.startUp();
- window.startUp = undefined;
+ if ( console && console.log ) {
+ msg = ( e ? 'Exception' : 'Error' ) + ' in ' + source;
+ if ( module ) {
+ msg += ' in module ' + module;
+ }
+ msg += ( e ? ':' : '.' );
+ console.log( msg );
+
+ // If we have an exception object, log it to the error channel to trigger a
+ // proper stacktraces in browsers that support it. No fallback as we have no browsers
+ // that don't support error(), but do support log().
+ if ( e && console.error ) {
+ console.error( String( e ), e );
+ }
+ }
}
+ // subscribe to error streams
+ mw.trackSubscribe( 'resourceloader.exception', log );
+ mw.trackSubscribe( 'resourceloader.assert', log );
+
+ // Attach to window and globally alias
+ window.mw = window.mediaWiki = mw;
}( jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.notification.js b/resources/src/mediawiki/mediawiki.notification.js
index 1968aa94..132c334f 100644
--- a/resources/src/mediawiki/mediawiki.notification.js
+++ b/resources/src/mediawiki/mediawiki.notification.js
@@ -12,7 +12,7 @@
/**
* A Notification object for 1 message.
*
- * The "_" in the name is to avoid a bug (http://github.com/senchalabs/jsduck/issues/304).
+ * The underscore in the name is to avoid a bug <https://github.com/senchalabs/jsduck/issues/304>.
* It is not part of the actual class name.
*
* @class mw.Notification_
diff --git a/resources/src/mediawiki/mediawiki.pager.tablePager.less b/resources/src/mediawiki/mediawiki.pager.tablePager.less
index d37aec5b..822c8147 100644
--- a/resources/src/mediawiki/mediawiki.pager.tablePager.less
+++ b/resources/src/mediawiki/mediawiki.pager.tablePager.less
@@ -37,48 +37,48 @@
.TablePager_nav td.TablePager_nav-first .TablePager_nav-disabled {
padding-top: 25px;
- /* @embed */
- background: url(images/pager-arrow-disabled-fastforward-rtl.png) center top no-repeat;
+ background: none center top no-repeat;
+ .background-image-svg('images/pager-arrow-disabled-fastforward-rtl.svg', 'images/pager-arrow-disabled-fastforward-rtl.png');
}
.TablePager_nav td.TablePager_nav-prev .TablePager_nav-disabled {
padding-top: 25px;
- /* @embed */
- background: url(images/pager-arrow-disabled-forward-rtl.png) center top no-repeat;
+ background: none center top no-repeat;
+ .background-image-svg('images/pager-arrow-disabled-forward-rtl.svg', 'images/pager-arrow-disabled-forward-rtl.png');
}
.TablePager_nav td.TablePager_nav-next .TablePager_nav-disabled {
padding-top: 25px;
- /* @embed */
- background: url(images/pager-arrow-disabled-forward-ltr.png) center top no-repeat;
+ background: none center top no-repeat;
+ .background-image-svg('images/pager-arrow-disabled-forward-ltr.svg', 'images/pager-arrow-disabled-forward-ltr.png');
}
.TablePager_nav td.TablePager_nav-last .TablePager_nav-disabled {
padding-top: 25px;
- /* @embed */
- background: url(images/pager-arrow-disabled-fastforward-ltr.png) center top no-repeat;
+ background: none center top no-repeat;
+ .background-image-svg('images/pager-arrow-disabled-fastforward-ltr.svg', 'images/pager-arrow-disabled-fastforward-ltr.png');
}
.TablePager_nav td.TablePager_nav-first .TablePager_nav-enabled {
padding-top: 25px;
- /* @embed */
- background: url(images/pager-arrow-fastforward-rtl.png) center top no-repeat;
+ background: none center top no-repeat;
+ .background-image-svg('images/pager-arrow-fastforward-rtl.svg', 'images/pager-arrow-fastforward-rtl.png');
}
.TablePager_nav td.TablePager_nav-prev .TablePager_nav-enabled {
padding-top: 25px;
- /* @embed */
- background: url(images/pager-arrow-forward-rtl.png) center top no-repeat;
+ background: none center top no-repeat;
+ .background-image-svg('images/pager-arrow-forward-rtl.svg', 'images/pager-arrow-forward-rtl.png');
}
.TablePager_nav td.TablePager_nav-next .TablePager_nav-enabled {
padding-top: 25px;
- /* @embed */
- background: url(images/pager-arrow-forward-ltr.png) center top no-repeat;
+ background: none center top no-repeat;
+ .background-image-svg('images/pager-arrow-forward-ltr.svg', 'images/pager-arrow-forward-ltr.png');
}
.TablePager_nav td.TablePager_nav-last .TablePager_nav-enabled {
padding-top: 25px;
- /* @embed */
- background: url(images/pager-arrow-fastforward-ltr.png) center top no-repeat;
+ background: none center top no-repeat;
+ .background-image-svg('images/pager-arrow-fastforward-ltr.svg', 'images/pager-arrow-fastforward-ltr.png');
}
diff --git a/resources/src/mediawiki/mediawiki.searchSuggest.js b/resources/src/mediawiki/mediawiki.searchSuggest.js
index a214cb3f..7b7ccf3f 100644
--- a/resources/src/mediawiki/mediawiki.searchSuggest.js
+++ b/resources/src/mediawiki/mediawiki.searchSuggest.js
@@ -41,10 +41,7 @@
baseHref = $form.attr( 'action' );
baseHref += baseHref.indexOf( '?' ) > -1 ? '&' : '?';
- linkParams = {};
- $.each( $form.serializeArray(), function ( idx, obj ) {
- linkParams[ obj.name ] = obj.value;
- } );
+ linkParams = $form.serializeObject();
return {
textParam: context.data.$textbox.attr( 'name' ),
@@ -122,7 +119,7 @@
];
$( searchboxesSelectors.join( ', ' ) )
.suggestions( {
- fetch: function ( query, response ) {
+ fetch: function ( query, response, maxRows ) {
var node = this[0];
api = api || new mw.Api();
@@ -131,6 +128,7 @@
action: 'opensearch',
search: query,
namespace: 0,
+ limit: maxRows,
suggest: ''
} ).done( function ( data ) {
response( data[ 1 ] );
diff --git a/resources/src/mediawiki/mediawiki.sectionAnchor.css b/resources/src/mediawiki/mediawiki.sectionAnchor.css
new file mode 100644
index 00000000..f8f00221
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.sectionAnchor.css
@@ -0,0 +1,3 @@
+.mw-headline-anchor {
+ display: none;
+}
diff --git a/resources/src/mediawiki/mediawiki.startUp.js b/resources/src/mediawiki/mediawiki.startUp.js
new file mode 100644
index 00000000..028784c2
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.startUp.js
@@ -0,0 +1,11 @@
+/*!
+ * Auto-register from pre-loaded startup scripts
+ */
+( function ( $ ) {
+ 'use strict';
+
+ if ( $.isFunction( window.startUp ) ) {
+ window.startUp();
+ window.startUp = undefined;
+ }
+}( jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.template.js b/resources/src/mediawiki/mediawiki.template.js
new file mode 100644
index 00000000..61bbb0d7
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.template.js
@@ -0,0 +1,123 @@
+/**
+ * @class mw.template
+ * @singleton
+ */
+( function ( mw, $ ) {
+ var compiledTemplates = {},
+ compilers = {};
+
+ mw.template = {
+ /**
+ * Register a new compiler and template.
+ *
+ * @param {string} name of compiler. Should also match with any file extensions of templates that want to use it.
+ * @param {Function} compiler which must implement a compile function
+ */
+ registerCompiler: function ( name, compiler ) {
+ if ( !compiler.compile ) {
+ throw new Error( 'Compiler must implement compile method.' );
+ }
+ compilers[name] = compiler;
+ },
+
+ /**
+ * Get the name of the compiler associated with a template based on its name.
+ *
+ * @param {string} templateName Name of template (including file suffix)
+ * @return {String} Name of compiler
+ */
+ getCompilerName: function ( templateName ) {
+ var templateParts = templateName.split( '.' );
+
+ if ( templateParts.length < 2 ) {
+ throw new Error( 'Unable to identify compiler. Template name must have a suffix.' );
+ }
+ return templateParts[ templateParts.length - 1 ];
+ },
+
+ /**
+ * Get the compiler for a given compiler name.
+ *
+ * @param {string} compilerName Name of the compiler
+ * @return {Object} The compiler associated with that name
+ */
+ getCompiler: function ( compilerName ) {
+ var compiler = compilers[ compilerName ];
+ if ( !compiler ) {
+ throw new Error( 'Unknown compiler ' + compilerName );
+ }
+ return compiler;
+ },
+
+ /**
+ * Register a template associated with a module.
+ *
+ * Compiles the newly added template based on the suffix in its name.
+ *
+ * @param {string} moduleName Name of ResourceLoader module to get the template from
+ * @param {string} templateName Name of template to add including file extension
+ * @param {string} templateBody Contents of a template (e.g. html markup)
+ * @return {Function} Compiled template
+ */
+ add: function ( moduleName, templateName, templateBody ) {
+ var compiledTemplate,
+ compilerName = this.getCompilerName( templateName );
+
+ if ( !compiledTemplates[moduleName] ) {
+ compiledTemplates[moduleName] = {};
+ }
+
+ compiledTemplate = this.compile( templateBody, compilerName );
+ compiledTemplates[moduleName][ templateName ] = compiledTemplate;
+ return compiledTemplate;
+ },
+
+ /**
+ * Retrieve a template by module and template name.
+ *
+ * @param {string} moduleName Name of the module to retrieve the template from
+ * @param {string} templateName Name of template to be retrieved
+ * @return {Object} Compiled template
+ */
+ get: function ( moduleName, templateName ) {
+ var moduleTemplates, compiledTemplate;
+
+ // Check if the template has already been compiled, compile it if not
+ if ( !compiledTemplates[ moduleName ] || !compiledTemplates[ moduleName ][ templateName ] ) {
+ moduleTemplates = mw.templates.get( moduleName );
+ if ( !moduleTemplates || !moduleTemplates[ templateName ] ) {
+ throw new Error( 'Template ' + templateName + ' not found in module ' + moduleName );
+ }
+
+ // Add compiled version
+ compiledTemplate = this.add( moduleName, templateName, moduleTemplates[ templateName ] );
+ } else {
+ compiledTemplate = compiledTemplates[ moduleName ][ templateName ];
+ }
+ return compiledTemplate;
+ },
+
+ /**
+ * Wrap our template engine of choice.
+ *
+ * @param {string} templateBody Template body
+ * @param {string} compilerName The name of a registered compiler
+ * @return {Object} Template interface
+ */
+ compile: function ( templateBody, compilerName ) {
+ return this.getCompiler( compilerName ).compile( templateBody );
+ }
+ };
+
+ // Register basic html compiler
+ mw.template.registerCompiler( 'html', {
+ compile: function ( src ) {
+ return {
+ render: function () {
+ return $( $.parseHTML( $.trim( src ) ) );
+ }
+ };
+ }
+ } );
+
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.template.mustache.js b/resources/src/mediawiki/mediawiki.template.mustache.js
new file mode 100644
index 00000000..dcc3842b
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.template.mustache.js
@@ -0,0 +1,14 @@
+/*global Mustache */
+( function ( mw, $ ) {
+ // Register mustache compiler
+ mw.template.registerCompiler( 'mustache', {
+ compile: function ( src ) {
+ return {
+ render: function ( data ) {
+ return $.parseHTML( Mustache.render( src, data ) );
+ }
+ };
+ }
+ } );
+
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.user.js b/resources/src/mediawiki/mediawiki.user.js
index e93707ec..817c856c 100644
--- a/resources/src/mediawiki/mediawiki.user.js
+++ b/resources/src/mediawiki/mediawiki.user.js
@@ -3,12 +3,9 @@
* @singleton
*/
( function ( mw, $ ) {
- var user,
+ var i,
deferreds = {},
- // Extend the skeleton mw.user from mediawiki.js
- // This is kind of ugly but we're stuck with this for b/c reasons
- options = mw.user.options || new mw.Map(),
- tokens = mw.user.tokens || new mw.Map();
+ byteToHex = [];
/**
* Get the current user's groups or rights
@@ -44,27 +41,65 @@
return deferreds[info].promise();
}
- mw.user = user = {
- options: options,
- tokens: tokens,
+ // Map from numbers 0-255 to a hex string (with padding)
+ for ( i = 0; i < 256; i++ ) {
+ // Padding: Add a full byte (0x100, 256) and strip the extra character
+ byteToHex[i] = ( i + 256 ).toString( 16 ).slice( 1 );
+ }
+
+ // mw.user with the properties options and tokens gets defined in mediawiki.js.
+ $.extend( mw.user, {
/**
- * Generate a random user session ID (32 alpha-numeric characters)
+ * Generate a random user session ID.
*
* This information would potentially be stored in a cookie to identify a user during a
- * session or series of sessions. Its uniqueness should not be depended on.
+ * session or series of sessions. Its uniqueness should not be depended on unless the
+ * browser supports the crypto API.
+ *
+ * Known problems with Math.random():
+ * Using the Math.random function we have seen sets
+ * with 1% of non uniques among 200,000 values with Safari providing most of these.
+ * Given the prevalence of Safari in mobile the percentage of duplicates in
+ * mobile usages of this code is probably higher.
*
- * @return {string} Random set of 32 alpha-numeric characters
+ * Rationale:
+ * We need about 64 bits to make sure that probability of collision
+ * on 500 million (5*10^8) is <= 1%
+ * See https://en.wikipedia.org/wiki/Birthday_problem#Probability_table
+ *
+ * @return {string} 64 bit integer in hex format, padded
*/
generateRandomSessionId: function () {
- var i, r,
- id = '',
- seed = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
- for ( i = 0; i < 32; i++ ) {
- r = Math.floor( Math.random() * seed.length );
- id += seed.charAt( r );
+ /*jshint bitwise:false */
+ var rnds, i, r,
+ hexRnds = new Array( 8 ),
+ // Support: IE 11
+ crypto = window.crypto || window.msCrypto;
+
+ // Based on https://github.com/broofa/node-uuid/blob/bfd9f96127/uuid.js
+ if ( crypto && crypto.getRandomValues ) {
+ // Fill an array with 8 random values, each of which is 8 bits.
+ // Note that Uint8Array is array-like but does not implement Array.
+ rnds = new Uint8Array( 8 );
+ crypto.getRandomValues( rnds );
+ } else {
+ rnds = new Array( 8 );
+ for ( i = 0; i < 8; i++ ) {
+ if ( ( i & 3 ) === 0 ) {
+ r = Math.random() * 0x100000000;
+ }
+ rnds[i] = r >>> ( ( i & 3 ) << 3 ) & 255;
+ }
+ }
+ // Convert from number to hex
+ for ( i = 0; i < 8; i++ ) {
+ hexRnds[i] = byteToHex[rnds[i]];
}
- return id;
+
+ // Concatenation of two random integers with entrophy n and m
+ // returns a string with entrophy n+m if those strings are independent
+ return hexRnds.join( '' );
},
/**
@@ -95,15 +130,15 @@
*/
getRegistration: function () {
var registration = mw.config.get( 'wgUserRegistration' );
- if ( user.isAnon() ) {
+ if ( mw.user.isAnon() ) {
return false;
- } else if ( registration === null ) {
+ }
+ if ( registration === null ) {
// Information may not be available if they signed up before
// MW began storing this.
return null;
- } else {
- return new Date( registration );
}
+ return new Date( registration );
},
/**
@@ -112,7 +147,7 @@
* @return {boolean}
*/
isAnon: function () {
- return user.getName() === null;
+ return mw.user.getName() === null;
},
/**
@@ -126,7 +161,7 @@
sessionId: function () {
var sessionId = $.cookie( 'mediaWiki.user.sessionId' );
if ( sessionId === undefined || sessionId === null ) {
- sessionId = user.generateRandomSessionId();
+ sessionId = mw.user.generateRandomSessionId();
$.cookie( 'mediaWiki.user.sessionId', sessionId, { expires: null, path: '/' } );
}
return sessionId;
@@ -140,7 +175,7 @@
* @return {string} User name or random session ID
*/
id: function () {
- return user.getName() || user.sessionId();
+ return mw.user.getName() || mw.user.sessionId();
},
/**
@@ -239,20 +274,6 @@
getRights: function ( callback ) {
return getUserInfo( 'rights' ).done( callback );
}
- };
-
- /**
- * @method name
- * @inheritdoc #getName
- * @deprecated since 1.20 Use #getName instead
- */
- mw.log.deprecate( user, 'name', user.getName, 'Use mw.user.getName instead.' );
-
- /**
- * @method anonymous
- * @inheritdoc #isAnon
- * @deprecated since 1.20 Use #isAnon instead
- */
- mw.log.deprecate( user, 'anonymous', user.isAnon, 'Use mw.user.isAnon instead.' );
+ } );
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.userSuggest.js b/resources/src/mediawiki/mediawiki.userSuggest.js
new file mode 100644
index 00000000..3964f0b2
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.userSuggest.js
@@ -0,0 +1,41 @@
+/*!
+ * Add autocomplete suggestions for names of registered users.
+ */
+( function ( mw, $ ) {
+ var api, config;
+
+ config = {
+ fetch: function ( userInput, response, maxRows ) {
+ var node = this[0];
+
+ api = api || new mw.Api();
+
+ $.data( node, 'request', api.get( {
+ action: 'query',
+ list: 'allusers',
+ // Prefix of list=allusers is case sensitive. Normalise first
+ // character to uppercase so that "fo" may yield "Foo".
+ auprefix: userInput.charAt( 0 ).toUpperCase() + userInput.slice( 1 ),
+ aulimit: maxRows
+ } ).done( function ( data ) {
+ var users = $.map( data.query.allusers, function ( userObj ) {
+ return userObj.name;
+ } );
+ response( users );
+ } ) );
+ },
+ cancel: function () {
+ var node = this[0],
+ request = $.data( node, 'request' );
+
+ if ( request ) {
+ request.abort();
+ $.removeData( node, 'request' );
+ }
+ }
+ };
+
+ $( function () {
+ $( '.mw-autocomplete-user' ).suggestions( config );
+ } );
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.util.js b/resources/src/mediawiki/mediawiki.util.js
index 26629137..6723e5f9 100644
--- a/resources/src/mediawiki/mediawiki.util.js
+++ b/resources/src/mediawiki/mediawiki.util.js
@@ -88,7 +88,7 @@
/**
* Get the link to a page name (relative to `wgServer`),
*
- * @param {string} str Page name
+ * @param {string|null} [str=wgPageName] Page name
* @param {Object} [params] A mapping of query parameter names to values,
* e.g. `{ action: 'edit' }`
* @return {string} Url of the page with name of `str`
@@ -151,12 +151,12 @@
* Returns null if not found.
*
* @param {string} param The parameter name.
- * @param {string} [url=document.location.href] URL to search through, defaulting to the current document's URL.
+ * @param {string} [url=location.href] URL to search through, defaulting to the current browsing location.
* @return {Mixed} Parameter value or null.
*/
getParamValue: function ( param, url ) {
if ( url === undefined ) {
- url = document.location.href;
+ url = location.href;
}
// Get last match, stop at hash
var re = new RegExp( '^[^#]*[&?]' + $.escapeRE( param ) + '=([^&#]*)' ),
@@ -196,7 +196,7 @@
* p-cactions (Content actions), p-personal (Personal tools),
* p-navigation (Navigation), p-tb (Toolbox)
*
- * The first three paramters are required, the others are optional and
+ * The first three parameters are required, the others are optional and
* may be null. Though providing an id and tooltip is recommended.
*
* By default the new link will be added to the end of the list. To
@@ -228,7 +228,7 @@
addPortletLink: function ( portlet, href, text, id, tooltip, accesskey, nextnode ) {
var $item, $link, $portlet, $ul;
- // Check if there's atleast 3 arguments to prevent a TypeError
+ // Check if there's at least 3 arguments to prevent a TypeError
if ( arguments.length < 3 ) {
return null;
}
@@ -286,30 +286,38 @@
}
if ( tooltip ) {
- $link.attr( 'title', tooltip ).updateTooltipAccessKeys();
+ $link.attr( 'title', tooltip );
}
if ( nextnode ) {
+ // Case: nextnode is a DOM element (was the only option before MW 1.17, in wikibits.js)
+ // Case: nextnode is a CSS selector for jQuery
if ( nextnode.nodeType || typeof nextnode === 'string' ) {
- // nextnode is a DOM element (was the only option before MW 1.17, in wikibits.js)
- // or nextnode is a CSS selector for jQuery
nextnode = $ul.find( nextnode );
- } else if ( !nextnode.jquery || ( nextnode.length && nextnode[0].parentNode !== $ul[0] ) ) {
- // Fallback
- $ul.append( $item );
- return $item[0];
+ } else if ( !nextnode.jquery ) {
+ // Error: Invalid nextnode
+ nextnode = undefined;
}
- if ( nextnode.length === 1 ) {
- // nextnode is a jQuery object that represents exactly one element
- nextnode.before( $item );
- return $item[0];
+ if ( nextnode && ( nextnode.length !== 1 || nextnode[0].parentNode !== $ul[0] ) ) {
+ // Error: nextnode must resolve to a single node
+ // Error: nextnode must have the associated <ul> as its parent
+ nextnode = undefined;
}
}
- // Fallback (this is the default behavior)
- $ul.append( $item );
- return $item[0];
+ // Case: nextnode is a jQuery-wrapped DOM element
+ if ( nextnode ) {
+ nextnode.before( $item );
+ } else {
+ // Fallback (this is the default behavior)
+ $ul.append( $item );
+ }
+
+ // Update tooltip for the access key after inserting into DOM
+ // to get a localized access key label (bug 67946).
+ $link.updateTooltipAccessKeys();
+ return $item[0];
},
/**
@@ -332,7 +340,7 @@
// HTML5 defines a string as valid e-mail address if it matches
// the ABNF:
- // 1 * ( atext / "." ) "@" ldh-str 1*( "." ldh-str )
+ // 1 * ( atext / "." ) "@" ldh-str 1*( "." ldh-str )
// With:
// - atext : defined in RFC 5322 section 3.2.3
// - ldh-str : defined in RFC 1034 section 3.5
@@ -353,12 +361,12 @@
rfc5322Atext = 'a-z0-9!#$%&\'*+\\-/=?^_`{|}~';
// Next define the RFC 1034 'ldh-str'
- // <domain> ::= <subdomain> | " "
- // <subdomain> ::= <label> | <subdomain> "." <label>
- // <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
- // <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
- // <let-dig-hyp> ::= <let-dig> | "-"
- // <let-dig> ::= <letter> | <digit>
+ // <domain> ::= <subdomain> | " "
+ // <subdomain> ::= <label> | <subdomain> "." <label>
+ // <label> ::= <letter> [ [ <ldh-str> ] <let-dig> ]
+ // <ldh-str> ::= <let-dig-hyp> | <let-dig-hyp> <ldh-str>
+ // <let-dig-hyp> ::= <let-dig> | "-"
+ // <let-dig> ::= <letter> | <digit>
rfc1034LdhStr = 'a-z0-9\\-';
html5EmailRegexp = new RegExp(
@@ -435,6 +443,19 @@
return address.search( new RegExp( '^' + RE_IPV6_ADD + block + '$' ) ) !== -1
&& address.search( /::/ ) !== -1 && address.search( /::.*::/ ) === -1;
+ },
+
+ /**
+ * Check whether a string is an IP address
+ *
+ * @since 1.25
+ * @param {string} address String to check
+ * @param {boolean} allowBlock True if a block of IPs should be allowed
+ * @return {boolean}
+ */
+ isIPAddress: function ( address, allowBlock ) {
+ return util.isIPv4Address( address, allowBlock ) ||
+ util.isIPv6Address( address, allowBlock );
}
};