summaryrefslogtreecommitdiff
path: root/resources
diff options
context:
space:
mode:
Diffstat (limited to 'resources')
-rw-r--r--resources/Resources.php513
-rw-r--r--resources/ResourcesOOUI.php132
-rw-r--r--resources/lib/es5-shim/es5-shim.js782
-rw-r--r--resources/lib/jquery.client/jquery.client.js9
-rw-r--r--resources/lib/jquery.i18n/CREDITS9
-rw-r--r--resources/lib/jquery.i18n/GPL-LICENSE339
-rw-r--r--resources/lib/jquery.i18n/MIT-LICENSE21
-rw-r--r--resources/lib/jquery.i18n/README.md432
-rw-r--r--resources/lib/jquery.i18n/src/jquery.i18n.emitter.bidi.js88
-rw-r--r--resources/lib/jquery.i18n/src/jquery.i18n.emitter.js168
-rw-r--r--resources/lib/jquery.i18n/src/jquery.i18n.fallbacks.js186
-rw-r--r--resources/lib/jquery.i18n/src/jquery.i18n.js287
-rw-r--r--resources/lib/jquery.i18n/src/jquery.i18n.language.js472
-rw-r--r--resources/lib/jquery.i18n/src/jquery.i18n.messagestore.js125
-rw-r--r--resources/lib/jquery.i18n/src/jquery.i18n.parser.js309
-rw-r--r--resources/lib/jquery.i18n/src/languages/bs.js22
-rw-r--r--resources/lib/jquery.i18n/src/languages/dsb.js22
-rw-r--r--resources/lib/jquery.i18n/src/languages/fi.js49
-rw-r--r--resources/lib/jquery.i18n/src/languages/ga.js38
-rw-r--r--resources/lib/jquery.i18n/src/languages/he.js31
-rw-r--r--resources/lib/jquery.i18n/src/languages/hsb.js21
-rw-r--r--resources/lib/jquery.i18n/src/languages/hu.js26
-rw-r--r--resources/lib/jquery.i18n/src/languages/hy.js25
-rw-r--r--resources/lib/jquery.i18n/src/languages/la.js54
-rw-r--r--resources/lib/jquery.i18n/src/languages/ml.js98
-rw-r--r--resources/lib/jquery.i18n/src/languages/os.js76
-rw-r--r--resources/lib/jquery.i18n/src/languages/ru.js29
-rw-r--r--resources/lib/jquery.i18n/src/languages/sl.js26
-rw-r--r--resources/lib/jquery.i18n/src/languages/uk.js39
-rw-r--r--resources/lib/json2/json2.js126
-rw-r--r--resources/lib/mustache/LICENSE10
-rw-r--r--resources/lib/oojs-ui/i18n/af.json8
-rw-r--r--resources/lib/oojs-ui/i18n/ar.json10
-rw-r--r--resources/lib/oojs-ui/i18n/arq.json7
-rw-r--r--resources/lib/oojs-ui/i18n/as.json25
-rw-r--r--resources/lib/oojs-ui/i18n/ast.json9
-rw-r--r--resources/lib/oojs-ui/i18n/be-tarask.json21
-rw-r--r--resources/lib/oojs-ui/i18n/be.json17
-rw-r--r--resources/lib/oojs-ui/i18n/bg.json13
-rw-r--r--resources/lib/oojs-ui/i18n/bn.json9
-rw-r--r--resources/lib/oojs-ui/i18n/bs.json5
-rw-r--r--resources/lib/oojs-ui/i18n/ca.json11
-rw-r--r--resources/lib/oojs-ui/i18n/ckb.json13
-rw-r--r--resources/lib/oojs-ui/i18n/cs.json4
-rw-r--r--resources/lib/oojs-ui/i18n/cu.json3
-rw-r--r--resources/lib/oojs-ui/i18n/da.json7
-rw-r--r--resources/lib/oojs-ui/i18n/de.json6
-rw-r--r--resources/lib/oojs-ui/i18n/dty.json18
-rw-r--r--resources/lib/oojs-ui/i18n/el.json8
-rw-r--r--resources/lib/oojs-ui/i18n/en-ca.json22
-rw-r--r--resources/lib/oojs-ui/i18n/en.json6
-rw-r--r--resources/lib/oojs-ui/i18n/eo.json17
-rw-r--r--resources/lib/oojs-ui/i18n/es.json6
-rw-r--r--resources/lib/oojs-ui/i18n/et.json9
-rw-r--r--resources/lib/oojs-ui/i18n/eu.json10
-rw-r--r--resources/lib/oojs-ui/i18n/fa.json15
-rw-r--r--resources/lib/oojs-ui/i18n/fi.json14
-rw-r--r--resources/lib/oojs-ui/i18n/fr.json18
-rw-r--r--resources/lib/oojs-ui/i18n/gl.json6
-rw-r--r--resources/lib/oojs-ui/i18n/glk.json23
-rw-r--r--resources/lib/oojs-ui/i18n/gu.json12
-rw-r--r--resources/lib/oojs-ui/i18n/he.json6
-rw-r--r--resources/lib/oojs-ui/i18n/hi.json7
-rw-r--r--resources/lib/oojs-ui/i18n/hrx.json12
-rw-r--r--resources/lib/oojs-ui/i18n/hu-formal.json21
-rw-r--r--resources/lib/oojs-ui/i18n/hu.json10
-rw-r--r--resources/lib/oojs-ui/i18n/hy.json7
-rw-r--r--resources/lib/oojs-ui/i18n/ia.json9
-rw-r--r--resources/lib/oojs-ui/i18n/id.json4
-rw-r--r--resources/lib/oojs-ui/i18n/ilo.json4
-rw-r--r--resources/lib/oojs-ui/i18n/is.json6
-rw-r--r--resources/lib/oojs-ui/i18n/it.json13
-rw-r--r--resources/lib/oojs-ui/i18n/ja.json9
-rw-r--r--resources/lib/oojs-ui/i18n/jv.json18
-rw-r--r--resources/lib/oojs-ui/i18n/ka.json4
-rw-r--r--resources/lib/oojs-ui/i18n/km.json23
-rw-r--r--resources/lib/oojs-ui/i18n/ko.json13
-rw-r--r--resources/lib/oojs-ui/i18n/krc.json4
-rw-r--r--resources/lib/oojs-ui/i18n/krl.json10
-rw-r--r--resources/lib/oojs-ui/i18n/ksh.json5
-rw-r--r--resources/lib/oojs-ui/i18n/ku-latn.json7
-rw-r--r--resources/lib/oojs-ui/i18n/la.json15
-rw-r--r--resources/lib/oojs-ui/i18n/lb.json5
-rw-r--r--resources/lib/oojs-ui/i18n/li.json21
-rw-r--r--resources/lib/oojs-ui/i18n/lt.json20
-rw-r--r--resources/lib/oojs-ui/i18n/luz.json21
-rw-r--r--resources/lib/oojs-ui/i18n/mk.json6
-rw-r--r--resources/lib/oojs-ui/i18n/ml.json18
-rw-r--r--resources/lib/oojs-ui/i18n/mr.json11
-rw-r--r--resources/lib/oojs-ui/i18n/ms.json11
-rw-r--r--resources/lib/oojs-ui/i18n/nap.json21
-rw-r--r--resources/lib/oojs-ui/i18n/nb.json6
-rw-r--r--resources/lib/oojs-ui/i18n/nl.json4
-rw-r--r--resources/lib/oojs-ui/i18n/oc.json9
-rw-r--r--resources/lib/oojs-ui/i18n/olo.json23
-rw-r--r--resources/lib/oojs-ui/i18n/om.json4
-rw-r--r--resources/lib/oojs-ui/i18n/or.json7
-rw-r--r--resources/lib/oojs-ui/i18n/pa.json9
-rw-r--r--resources/lib/oojs-ui/i18n/pl.json11
-rw-r--r--resources/lib/oojs-ui/i18n/pms.json13
-rw-r--r--resources/lib/oojs-ui/i18n/ps.json6
-rw-r--r--resources/lib/oojs-ui/i18n/pt-br.json17
-rw-r--r--resources/lib/oojs-ui/i18n/pt.json8
-rw-r--r--resources/lib/oojs-ui/i18n/qqq.json6
-rw-r--r--resources/lib/oojs-ui/i18n/ro.json6
-rw-r--r--resources/lib/oojs-ui/i18n/roa-tara.json6
-rw-r--r--resources/lib/oojs-ui/i18n/ru.json9
-rw-r--r--resources/lib/oojs-ui/i18n/sa.json14
-rw-r--r--resources/lib/oojs-ui/i18n/sah.json16
-rw-r--r--resources/lib/oojs-ui/i18n/sco.json15
-rw-r--r--resources/lib/oojs-ui/i18n/sh.json14
-rw-r--r--resources/lib/oojs-ui/i18n/sk.json14
-rw-r--r--resources/lib/oojs-ui/i18n/sl.json4
-rw-r--r--resources/lib/oojs-ui/i18n/sq.json11
-rw-r--r--resources/lib/oojs-ui/i18n/sr-ec.json4
-rw-r--r--resources/lib/oojs-ui/i18n/su.json21
-rw-r--r--resources/lib/oojs-ui/i18n/sv.json9
-rw-r--r--resources/lib/oojs-ui/i18n/ta.json17
-rw-r--r--resources/lib/oojs-ui/i18n/te.json11
-rw-r--r--resources/lib/oojs-ui/i18n/tl.json13
-rw-r--r--resources/lib/oojs-ui/i18n/uk.json10
-rw-r--r--resources/lib/oojs-ui/i18n/vec.json11
-rw-r--r--resources/lib/oojs-ui/i18n/vi.json13
-rw-r--r--resources/lib/oojs-ui/i18n/xmf.json19
-rw-r--r--resources/lib/oojs-ui/i18n/yi.json7
-rw-r--r--resources/lib/oojs-ui/i18n/yue.json16
-rw-r--r--resources/lib/oojs-ui/i18n/zh-hans.json17
-rw-r--r--resources/lib/oojs-ui/i18n/zh-hant.json9
-rw-r--r--resources/lib/oojs-ui/oojs-ui-apex-noimages.css2956
-rw-r--r--resources/lib/oojs-ui/oojs-ui-apex.js28
-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.css931
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki.css3204
-rw-r--r--resources/lib/oojs-ui/oojs-ui-mediawiki.js19
-rw-r--r--resources/lib/oojs-ui/oojs-ui.js5869
-rw-r--r--resources/lib/oojs-ui/themes/apex/icons-editing-advanced.json79
-rw-r--r--resources/lib/oojs-ui/themes/apex/icons-editing-core.json24
-rw-r--r--resources/lib/oojs-ui/themes/apex/icons-editing-list.json22
-rw-r--r--resources/lib/oojs-ui/themes/apex/icons-editing-styling.json72
-rw-r--r--resources/lib/oojs-ui/themes/apex/icons-moderation.json33
-rw-r--r--resources/lib/oojs-ui/themes/apex/icons-movement.json27
-rw-r--r--resources/lib/oojs-ui/themes/apex/icons.json51
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/add.pngbin0 -> 144 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/add.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/advanced.pngbin0 -> 464 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/advanced.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/alert.pngbin0 -> 422 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/alert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/align-center.pngbin0 -> 165 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/align-center.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/align-float-left.pngbin0 -> 176 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/align-float-left.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/align-float-right.pngbin0 -> 176 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/align-float-right.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-ltr.pngbin0 -> 266 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-rtl.pngbin0 -> 264 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/arrow-ltr.pngbin0 -> 197 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/arrow-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/arrow-rtl.pngbin0 -> 198 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/arrow-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bigger-ltr.pngbin0 -> 341 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bigger-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bigger-rtl.pngbin0 -> 342 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bigger-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/block.pngbin0 -> 295 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/block.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-ltr.pngbin0 -> 309 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-rtl.pngbin0 -> 317 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-a.pngbin0 -> 276 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-a.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-ain.pngbin0 -> 284 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-ain.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-dad.pngbin0 -> 310 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-dad.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-armn-to.pngbin0 -> 342 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-armn-to.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-b.pngbin0 -> 219 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-b.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-be.pngbin0 -> 228 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-be.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-te.pngbin0 -> 145 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-te.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-zhe.pngbin0 -> 337 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-zhe.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-f.pngbin0 -> 150 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-f.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-g.pngbin0 -> 313 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-g.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-geor-man.pngbin0 -> 294 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-geor-man.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-l.pngbin0 -> 143 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-l.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-n.pngbin0 -> 176 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-n.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-v.pngbin0 -> 256 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/bold-v.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/calendar-ltr.pngbin0 -> 213 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/calendar-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/calendar-rtl.pngbin0 -> 216 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/calendar-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/cancel.pngbin0 -> 350 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/cancel.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/caret-ltr.pngbin0 -> 251 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/caret-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/caret-rtl.pngbin0 -> 252 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/caret-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/caretDown.pngbin0 -> 246 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/caretDown.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/caretUp.pngbin0 -> 243 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/caretUp.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/case-sensitive.pngbin0 -> 369 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/case-sensitive.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/check.pngbin0 -> 235 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/check.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/circle.pngbin0 -> 244 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/circle.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/close.pngbin0 -> 237 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/close.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/code.pngbin0 -> 272 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/code.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/collapse.pngbin0 -> 195 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/collapse.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/comment.pngbin0 -> 211 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/comment.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/downTriangle.pngbin0 -> 212 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/downTriangle.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/edit-ltr.pngbin0 -> 282 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/edit-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/edit-rtl.pngbin0 -> 287 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/edit-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/editLock-ltr.pngbin0 -> 312 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/editLock-ltr.svg8
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/editLock-rtl.pngbin0 -> 328 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/editLock-rtl.svg8
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/editUndo-ltr.pngbin0 -> 392 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/editUndo-ltr.svg11
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/editUndo-rtl.pngbin0 -> 379 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/editUndo-rtl.svg11
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/ellipsis.pngbin0 -> 166 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/ellipsis.svg14
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/expand.pngbin0 -> 196 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/expand.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/external-link-ltr.pngbin0 -> 239 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/external-link-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/external-link-rtl.pngbin0 -> 232 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/external-link-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/find-ltr.pngbin0 -> 307 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/find-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/find-rtl.pngbin0 -> 307 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/find-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/flag-ltr.pngbin0 -> 231 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/flag-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/flag-rtl.pngbin0 -> 237 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/flag-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-ltr.pngbin0 -> 301 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-ltr.svg16
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-rtl.pngbin0 -> 294 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-rtl.svg16
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/help-ltr.pngbin0 -> 528 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/help-ltr.svg10
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/help-rtl.pngbin0 -> 543 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/help-rtl.svg10
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/history.pngbin0 -> 541 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/history.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/indent-ltr.pngbin0 -> 243 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/indent-ltr.svg9
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/indent-rtl.pngbin0 -> 243 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/indent-rtl.svg9
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/info.pngbin0 -> 321 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/info.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/insert.pngbin0 -> 144 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/insert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-a.pngbin0 -> 284 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-a.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-keheh-jeem.pngbin0 -> 334 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-keheh-jeem.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-meem.pngbin0 -> 270 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-meem.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-armn-sha.pngbin0 -> 338 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-armn-sha.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-c.pngbin0 -> 301 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-c.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-d.pngbin0 -> 330 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-d.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-e.pngbin0 -> 256 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-e.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-geor-kan.pngbin0 -> 289 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-geor-kan.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-i.pngbin0 -> 218 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-i.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-k.pngbin0 -> 285 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-k.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-s.pngbin0 -> 323 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/italic-s.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/language.pngbin0 -> 402 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/language.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/layout-ltr.pngbin0 -> 166 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/layout-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/layout-rtl.pngbin0 -> 163 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/layout-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/link.pngbin0 -> 301 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/link.svg8
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/listBullet-ltr.pngbin0 -> 183 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/listBullet-ltr.svg11
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/listBullet-rtl.pngbin0 -> 176 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/listBullet-rtl.svg11
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-ltr.pngbin0 -> 257 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-ltr.svg11
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-rtl.pngbin0 -> 258 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-rtl.svg11
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/lock.pngbin0 -> 196 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/lock.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/menu.pngbin0 -> 172 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/menu.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/move-ltr.pngbin0 -> 219 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/move-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/move-rtl.pngbin0 -> 213 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/move-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/move.pngbin0 -> 249 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/move.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/newline-ltr.pngbin0 -> 263 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/newline-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/newline-rtl.pngbin0 -> 282 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/newline-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-ltr.pngbin0 -> 234 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-rtl.pngbin0 -> 228 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/notice.pngbin0 -> 254 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/notice.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/outdent-ltr.pngbin0 -> 239 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/outdent-ltr.svg9
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/outdent-rtl.pngbin0 -> 241 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/outdent-rtl.svg9
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/outline-ltr.pngbin0 -> 153 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/outline-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/outline-rtl.pngbin0 -> 154 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/outline-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/picture.pngbin0 -> 308 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/picture.svg8
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/puzzle-ltr.pngbin0 -> 327 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/puzzle-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/puzzle-rtl.pngbin0 -> 338 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/puzzle-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/quotes-ltr.pngbin0 -> 288 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/quotes-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/quotes-rtl.pngbin0 -> 276 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/quotes-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-ltr.pngbin0 -> 293 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-rtl.pngbin0 -> 285 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/redirect-ltr.pngbin0 -> 381 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/redirect-ltr.svg8
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/redirect-rtl.pngbin0 -> 381 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/redirect-rtl.svg9
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/regular-expression.pngbin0 -> 343 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/regular-expression.svg9
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/remove.pngbin0 -> 172 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/remove.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/search.pngbin0 -> 245 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/search.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/secure-link.pngbin0 -> 200 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/secure-link.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/settings.pngbin0 -> 191 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/settings.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/smaller-ltr.pngbin0 -> 341 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/smaller-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/smaller-rtl.pngbin0 -> 342 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/smaller-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/specialCharacter.pngbin0 -> 349 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/specialCharacter.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/star.pngbin0 -> 435 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/star.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-a.pngbin0 -> 299 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-a.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-s.pngbin0 -> 307 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-s.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-y.pngbin0 -> 237 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-y.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/subscript-ltr.pngbin0 -> 244 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/subscript-ltr.svg5
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/subscript-rtl.pngbin0 -> 240 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/subscript-rtl.svg5
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/superscript-ltr.pngbin0 -> 241 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/superscript-ltr.svg5
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/superscript-rtl.pngbin0 -> 240 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/superscript-rtl.svg5
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-caption.pngbin0 -> 154 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-caption.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-ltr.pngbin0 -> 164 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-rtl.pngbin0 -> 165 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-after.pngbin0 -> 153 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-after.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-before.pngbin0 -> 151 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-before.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-merge-cells.pngbin0 -> 220 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table-merge-cells.svg10
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table.pngbin0 -> 151 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/table.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/tag.pngbin0 -> 260 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/tag.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-ltr.pngbin0 -> 193 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-ltr.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-rtl.pngbin0 -> 202 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-rtl.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/text-dir-lefttoright.pngbin0 -> 224 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/text-dir-lefttoright.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/text-dir-righttoleft.pngbin0 -> 233 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/text-dir-righttoleft.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/text-style.pngbin0 -> 309 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/text-style.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/translation-ltr.pngbin0 -> 429 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/translation-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/translation-rtl.pngbin0 -> 434 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/translation-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/trash.pngbin0 -> 193 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/trash.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-ltr.pngbin0 -> 254 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-rtl.pngbin0 -> 280 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/unLock-ltr.pngbin0 -> 196 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/unLock-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/unLock-rtl.pngbin0 -> 198 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/unLock-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/unStar.pngbin0 -> 262 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/unStar.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/underline-a.pngbin0 -> 290 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/underline-a.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/underline-u.pngbin0 -> 205 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/underline-u.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/upTriangle.pngbin0 -> 203 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/upTriangle.svg4
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/wikiText.pngbin0 -> 163 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/wikiText.svg15
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/window.pngbin0 -> 251 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/icons/window.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/alert.pngbin0 -> 233 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/alert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/arrow-down.pngbin0 -> 169 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/arrow-down.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/arrow-ltr.pngbin0 -> 166 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/arrow-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/arrow-rtl.pngbin0 -> 171 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/arrow-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/arrow-up.pngbin0 -> 171 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/arrow-up.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/clear.pngbin0 -> 240 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/clear.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/required.pngbin0 -> 241 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/required.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/search-ltr.pngbin0 -> 232 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/search-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/search-rtl.pngbin0 -> 232 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/indicators/search-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/textures/pending.gifbin0 -> 2032 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/textures/transparency.pngbin0 -> 145 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/textures/transparency.svg7
-rw-r--r--resources/lib/oojs-ui/themes/apex/images/toolbar-shadow.pngbin0 -> 131 bytes
-rw-r--r--resources/lib/oojs-ui/themes/apex/indicators.json23
-rw-r--r--resources/lib/oojs-ui/themes/apex/textures.json8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-accessibility.json19
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-alerts.json39
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-content.json56
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-editing-advanced.json85
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-editing-core.json45
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-editing-list.json28
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-editing-styling.json78
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-interactions.json58
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-layout.json42
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-location.json25
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-media.json33
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-moderation.json59
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-movement.json33
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-user.json25
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons-wikimedia.json15
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/icons.json76
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/add.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.pngbin453 -> 443 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.pngbin404 -> 400 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.pngbin469 -> 460 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.pngbin594 -> 594 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.pngbin433 -> 422 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center-invert.pngbin0 -> 180 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left-invert.pngbin0 -> 193 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right-invert.pngbin0 -> 197 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr-invert.pngbin351 -> 336 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr-invert.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr.pngbin309 -> 292 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-ltr.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl-invert.pngbin331 -> 328 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl-invert.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl.pngbin286 -> 291 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arched-arrow-rtl.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr-invert.pngbin0 -> 205 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl-invert.pngbin0 -> 204 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr-invert.pngbin0 -> 208 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl-invert.pngbin0 -> 204 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr-invert.pngbin0 -> 332 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr-invert.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl-invert.pngbin0 -> 323 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl-invert.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr-invert.pngbin0 -> 375 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl-invert.pngbin0 -> 416 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.pngbin0 -> 283 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.pngbin0 -> 427 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.pngbin365 -> 365 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl-invert.pngbin0 -> 429 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.pngbin376 -> 370 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/beta-invert.pngbin0 -> 373 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/beta-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch-invert.pngbin0 -> 355 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr-invert.pngbin0 -> 378 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl-invert.pngbin0 -> 381 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/block.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a-invert.pngbin0 -> 301 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain-invert.pngbin0 -> 322 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain.pngbin289 -> 284 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad-invert.pngbin0 -> 348 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.pngbin315 -> 310 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to-invert.pngbin0 -> 378 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to.pngbin342 -> 342 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b-invert.pngbin0 -> 240 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be-invert.pngbin0 -> 250 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be.pngbin232 -> 228 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te-invert.pngbin0 -> 154 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe-invert.pngbin0 -> 375 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe.pngbin343 -> 337 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f-invert.pngbin0 -> 158 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g-invert.pngbin0 -> 373 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.pngbin315 -> 313 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man-invert.pngbin0 -> 325 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man.pngbin297 -> 294 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l-invert.pngbin0 -> 152 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n-invert.pngbin0 -> 176 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v-invert.pngbin0 -> 279 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr-invert.pngbin0 -> 262 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl-invert.pngbin0 -> 260 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr-invert.pngbin0 -> 239 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl-invert.pngbin0 -> 235 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bright.pngbin0 -> 422 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/bright.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr-invert.pngbin0 -> 233 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl-invert.pngbin0 -> 224 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr-invert.pngbin0 -> 255 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr.pngbin0 -> 213 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl-invert.pngbin0 -> 239 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl.pngbin0 -> 216 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.pngbin378 -> 376 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.pngbin351 -> 350 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr-invert.pngbin0 -> 271 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.pngbin250 -> 251 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl-invert.pngbin0 -> 284 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown-invert.pngbin0 -> 257 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp-invert.pngbin0 -> 263 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.pngbin252 -> 243 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive-invert.pngbin0 -> 434 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.pngbin368 -> 369 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/check-destructive.pngbin0 -> 261 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/check-destructive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr-invert.pngbin0 -> 245 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl-invert.pngbin0 -> 246 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/clear-invert.pngbin0 -> 338 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/clear-invert.svg6
-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-invert.pngbin0 -> 370 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/clock-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr-invert.pngbin333 -> 314 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.pngbin296 -> 282 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.pngbin357 -> 339 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.pngbin319 -> 299 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.pngbin297 -> 297 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/code.pngbin272 -> 272 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/code.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.pngbin204 -> 205 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.pngbin207 -> 195 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/comment.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr-invert.pngbin0 -> 284 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl-invert.pngbin0 -> 281 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle-invert.pngbin0 -> 217 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr-invert.pngbin0 -> 270 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl-invert.pngbin0 -> 275 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr-progressive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-invert.pngbin314 -> 316 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-progressive.pngbin480 -> 487 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl-progressive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.pngbin284 -> 287 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr-invert.pngbin447 -> 456 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.pngbin390 -> 392 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl-invert.pngbin439 -> 435 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.pngbin379 -> 379 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/expand.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr-invert.pngbin184 -> 251 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr.pngbin168 -> 239 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl-invert.pngbin180 -> 250 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl.pngbin164 -> 232 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/external-link-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eye-invert.pngbin0 -> 399 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eye-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.pngbin353 -> 368 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed-invert.pngbin0 -> 339 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.pngbin324 -> 315 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr-invert.pngbin0 -> 346 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.pngbin298 -> 307 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl-invert.pngbin0 -> 351 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.pngbin297 -> 307 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr-invert.pngbin306 -> 309 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.pngbin295 -> 301 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr-invert.pngbin0 -> 177 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl-invert.pngbin0 -> 179 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr-invert.pngbin0 -> 252 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl-invert.pngbin0 -> 253 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/halfBright.pngbin0 -> 354 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/halfBright.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/heart-invert.pngbin0 -> 299 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/heart-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr-invert.pngbin603 -> 606 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.pngbin529 -> 528 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl-invert.pngbin622 -> 615 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.pngbin543 -> 543 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.pngbin628 -> 629 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/history.pngbin543 -> 541 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/history.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr-invert.pngbin0 -> 229 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl-invert.pngbin0 -> 221 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr-invert.pngbin0 -> 268 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl-invert.pngbin0 -> 254 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr-invert.pngbin0 -> 310 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl-invert.pngbin0 -> 311 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr-invert.pngbin0 -> 211 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl-invert.pngbin0 -> 212 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.pngbin377 -> 359 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/info.pngbin328 -> 321 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/info.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/insert-invert.pngbin0 -> 148 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/insert-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a-invert.pngbin0 -> 321 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem-invert.pngbin0 -> 379 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem.pngbin333 -> 334 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem-invert.pngbin0 -> 301 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem.pngbin271 -> 270 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha-invert.pngbin0 -> 369 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha.pngbin339 -> 338 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c-invert.pngbin0 -> 353 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.pngbin300 -> 301 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d-invert.pngbin0 -> 378 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.pngbin324 -> 330 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e-invert.pngbin0 -> 280 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.pngbin254 -> 256 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan-invert.pngbin0 -> 318 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan.pngbin287 -> 289 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i-invert.pngbin0 -> 233 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.pngbin208 -> 218 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k-invert.pngbin0 -> 303 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s-invert.pngbin0 -> 372 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.pngbin321 -> 323 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr-invert.pngbin0 -> 203 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl-invert.pngbin0 -> 206 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr-invert.pngbin0 -> 315 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl-invert.pngbin0 -> 302 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr-invert.pngbin0 -> 195 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl-invert.pngbin0 -> 199 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/language-invert.pngbin0 -> 490 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/language-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/language.pngbin410 -> 402 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/language.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-ltr.pngbin0 -> 357 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-rtl.pngbin0 -> 357 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr-invert.pngbin0 -> 175 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl-invert.pngbin0 -> 170 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr-invert.pngbin467 -> 507 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr-invert.svg19
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.pngbin423 -> 436 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.svg19
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr-invert.pngbin0 -> 203 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl-invert.pngbin0 -> 184 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr-invert.pngbin0 -> 184 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl-invert.pngbin0 -> 196 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-destructive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-destructive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr-invert.pngbin0 -> 244 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl-invert.pngbin0 -> 252 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc-invert.pngbin0 -> 448 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons-invert.pngbin0 -> 575 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia-invert.pngbin0 -> 512 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.pngbin459 -> 459 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr-invert.pngbin0 -> 336 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl-invert.pngbin0 -> 354 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin-invert.pngbin0 -> 401 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr-invert.pngbin0 -> 410 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr-invert.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl-invert.pngbin0 -> 404 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl-invert.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.pngbin181 -> 246 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.svg16
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.pngbin170 -> 218 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.svg16
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr-invert.pngbin0 -> 328 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl-invert.pngbin0 -> 335 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/moon.pngbin0 -> 352 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/moon.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-invert.pngbin0 -> 256 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl-invert.pngbin221 -> 220 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.pngbin214 -> 213 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/move.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr-invert.pngbin0 -> 223 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl-invert.pngbin0 -> 239 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr-invert.pngbin0 -> 287 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.pngbin267 -> 263 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-invert.pngbin0 -> 296 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl-invert.svg6
-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-invert.pngbin0 -> 203 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl-invert.pngbin0 -> 201 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr-invert.pngbin0 -> 242 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl-invert.pngbin0 -> 233 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/notBright.pngbin0 -> 291 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/notBright.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/notice-invert.pngbin0 -> 276 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/notice-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/notice.pngbin0 -> 254 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/notice.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-invert.pngbin0 -> 325 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-progressive.pngbin0 -> 380 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-progressive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr.pngbin0 -> 299 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-invert.pngbin0 -> 332 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-progressive.pngbin0 -> 368 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-progressive.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl.pngbin0 -> 296 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr-invert.pngbin0 -> 210 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl-invert.pngbin0 -> 211 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr-invert.pngbin0 -> 163 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl-invert.pngbin0 -> 162 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr-invert.pngbin0 -> 238 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl-invert.pngbin0 -> 232 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.pngbin396 -> 335 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.pngbin350 -> 308 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr-invert.pngbin0 -> 331 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl-invert.pngbin0 -> 335 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr-invert.pngbin0 -> 235 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl-invert.pngbin0 -> 235 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr-invert.pngbin0 -> 349 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.pngbin344 -> 327 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl-invert.pngbin0 -> 372 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.pngbin360 -> 338 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr-invert.pngbin0 -> 347 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.pngbin319 -> 321 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.svg17
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl-invert.pngbin0 -> 351 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.pngbin326 -> 318 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.svg17
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr-invert.pngbin0 -> 315 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.pngbin293 -> 293 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl-invert.pngbin0 -> 306 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.pngbin287 -> 285 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr-invert.pngbin0 -> 444 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.pngbin382 -> 381 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl-invert.pngbin0 -> 440 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl-invert.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression-invert.pngbin0 -> 422 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression-invert.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.pngbin340 -> 343 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/remove.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize-invert.pngbin0 -> 461 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize-invert.svg9
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.pngbin402 -> 394 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr-invert.pngbin372 -> 372 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.pngbin350 -> 348 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl-invert.pngbin376 -> 386 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.pngbin341 -> 347 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link-invert.pngbin215 -> 215 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.pngbin201 -> 200 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/settings.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr-invert.pngbin0 -> 514 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl-invert.pngbin0 -> 530 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.pngbin446 -> 447 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr-invert.pngbin0 -> 382 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl-invert.pngbin0 -> 381 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-ltr.pngbin0 -> 287 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-ltr.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-rtl.pngbin0 -> 279 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-rtl.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter-invert.pngbin0 -> 413 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.pngbin360 -> 349 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr-invert.pngbin0 -> 175 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl-invert.pngbin0 -> 176 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr-invert.pngbin0 -> 175 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl-invert.pngbin0 -> 176 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr-invert.pngbin0 -> 187 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl-invert.pngbin0 -> 191 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/star-constructive.pngbin0 -> 643 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/star-constructive.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/star.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stop-invert.pngbin0 -> 440 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stop-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a-invert.pngbin0 -> 324 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s-invert.pngbin0 -> 339 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.pngbin306 -> 307 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y-invert.pngbin0 -> 264 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.pngbin244 -> 237 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr-progressive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl-progressive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr-invert.pngbin0 -> 272 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr-invert.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl-invert.pngbin0 -> 258 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl-invert.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr-invert.pngbin0 -> 461 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr-invert.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.pngbin409 -> 408 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl-invert.pngbin0 -> 455 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl-invert.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.pngbin392 -> 398 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr-invert.pngbin0 -> 271 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr-invert.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl-invert.pngbin0 -> 264 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl-invert.svg5
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption-invert.pngbin0 -> 164 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr-invert.pngbin0 -> 167 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl-invert.pngbin0 -> 169 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after-invert.pngbin0 -> 159 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before-invert.pngbin0 -> 161 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-invert.pngbin0 -> 158 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells-invert.pngbin0 -> 234 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells-invert.svg10
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells.svg12
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table.pngbin150 -> 151 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/table.svg3
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.pngbin419 -> 419 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.pngbin438 -> 442 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.pngbin295 -> 290 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.pngbin424 -> 426 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.pngbin403 -> 399 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.pngbin262 -> 260 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr-invert.pngbin0 -> 203 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl-invert.pngbin0 -> 212 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright-invert.pngbin0 -> 240 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft-invert.pngbin0 -> 251 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style-invert.pngbin0 -> 351 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.pngbin306 -> 309 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr-invert.pngbin0 -> 473 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl-invert.pngbin0 -> 489 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.pngbin437 -> 434 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-destructive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-destructive.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl-invert.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-constructive.pngbin0 -> 382 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-constructive.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a-invert.pngbin0 -> 328 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.pngbin295 -> 290 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u-invert.pngbin0 -> 221 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u-invert.svg7
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.pngbin220 -> 205 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle-invert.pngbin0 -> 214 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr-invert.pngbin0 -> 267 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl-invert.pngbin0 -> 270 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr-invert.pngbin0 -> 367 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl-invert.pngbin0 -> 363 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar-invert.pngbin0 -> 288 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr-invert.pngbin0 -> 321 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.pngbin288 -> 286 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl-invert.pngbin0 -> 321 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr-invert.pngbin0 -> 347 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl-invert.pngbin0 -> 358 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.pngbin238 -> 0 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/watchlist-ltr-invert.pngbin0 -> 338 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl-invert.pngbin0 -> 330 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.svg2
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText-invert.pngbin0 -> 171 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText-invert.svg15
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr-invert.pngbin0 -> 470 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.pngbin409 -> 399 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl-invert.pngbin0 -> 471 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl-invert.svg8
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/icons/window.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down-invert.pngbin184 -> 133 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down-invert.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.pngbin173 -> 134 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr-invert.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl-invert.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up-invert.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.svg14
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear-invert.pngbin0 -> 262 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear-invert.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear.pngbin0 -> 240 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear.svg6
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/required.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr-invert.pngbin251 -> 255 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.pngbin231 -> 232 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl-invert.pngbin261 -> 259 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl-invert.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.pngbin234 -> 232 bytes
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.svg4
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.svg15
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/indicators.json30
-rw-r--r--resources/lib/oojs-ui/themes/mediawiki/textures.json8
-rw-r--r--resources/lib/oojs/oojs.jquery.js103
-rw-r--r--resources/lib/phpjs-sha1/LICENSE.txt20
-rw-r--r--resources/lib/phpjs-sha1/sha1.js147
-rw-r--r--resources/lib/qunitjs/qunit.css17
-rw-r--r--resources/lib/qunitjs/qunit.js1389
-rw-r--r--resources/lib/sinonjs/sinon-1.10.3.js5073
-rw-r--r--resources/lib/sinonjs/sinon-1.15.4.js5949
-rw-r--r--resources/lib/sinonjs/sinon-ie-1.15.4.js (renamed from resources/lib/sinonjs/sinon-ie-1.10.3.js)59
-rw-r--r--resources/src/dom-level2-skip.js6
-rw-r--r--resources/src/jquery.tipsy/jquery.tipsy.js30
-rw-r--r--resources/src/jquery/jquery.accessKeyLabel.js6
-rw-r--r--resources/src/jquery/jquery.autoEllipsis.js38
-rw-r--r--resources/src/jquery/jquery.byteLimit.js29
-rw-r--r--resources/src/jquery/jquery.color.js12
-rw-r--r--resources/src/jquery/jquery.colorUtil.js150
-rw-r--r--resources/src/jquery/jquery.expandableField.js23
-rw-r--r--resources/src/jquery/jquery.farbtastic.js8
-rw-r--r--resources/src/jquery/jquery.getAttrs.js4
-rw-r--r--resources/src/jquery/jquery.hidpi.js59
-rw-r--r--resources/src/jquery/jquery.highlightText.js21
-rw-r--r--resources/src/jquery/jquery.localize.js8
-rw-r--r--resources/src/jquery/jquery.makeCollapsible.js9
-rw-r--r--resources/src/jquery/jquery.mwExtension.js37
-rw-r--r--resources/src/jquery/jquery.placeholder.js279
-rw-r--r--resources/src/jquery/jquery.qunit.completenessTest.js31
-rw-r--r--resources/src/jquery/jquery.spinner.js2
-rw-r--r--resources/src/jquery/jquery.suggestions.js58
-rw-r--r--resources/src/jquery/jquery.tablesorter.js419
-rw-r--r--resources/src/jquery/jquery.textSelection.js11
-rw-r--r--resources/src/mediawiki.action/images/checker.png (renamed from resources/src/mediawiki.legacy/images/checker.png)bin81 -> 81 bytes
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.collapsibleFooter.js40
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.css3
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js2
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.js51
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.preview.js87
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.edit.stash.js2
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.history.js2
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.view.filepage.css71
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.view.filepage.print.css8
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.view.metadata.css6
-rw-r--r--resources/src/mediawiki.action/mediawiki.action.view.postEdit.js28
-rw-r--r--resources/src/mediawiki.api/mediawiki.ForeignApi.js109
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.edit.js6
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.js124
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.login.js1
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.options.js4
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.parse.js2
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.upload.js391
-rw-r--r--resources/src/mediawiki.api/mediawiki.api.watch.js2
-rw-r--r--resources/src/mediawiki.language/languages/bs.js4
-rw-r--r--resources/src/mediawiki.language/languages/dsb.js4
-rw-r--r--resources/src/mediawiki.language/languages/fi.js4
-rw-r--r--resources/src/mediawiki.language/languages/ga.js4
-rw-r--r--resources/src/mediawiki.language/languages/he.js4
-rw-r--r--resources/src/mediawiki.language/languages/hsb.js4
-rw-r--r--resources/src/mediawiki.language/languages/hu.js4
-rw-r--r--resources/src/mediawiki.language/languages/hy.js4
-rw-r--r--resources/src/mediawiki.language/languages/la.js8
-rw-r--r--resources/src/mediawiki.language/languages/os.js4
-rw-r--r--resources/src/mediawiki.language/languages/ru.js4
-rw-r--r--resources/src/mediawiki.language/languages/sl.js4
-rw-r--r--resources/src/mediawiki.language/languages/uk.js18
-rw-r--r--resources/src/mediawiki.language/mediawiki.cldr.js2
-rw-r--r--resources/src/mediawiki.language/mediawiki.language.init.js10
-rw-r--r--resources/src/mediawiki.language/mediawiki.language.js26
-rw-r--r--resources/src/mediawiki.language/mediawiki.language.numbers.js96
-rw-r--r--resources/src/mediawiki.language/specialcharacters.json446
-rw-r--r--resources/src/mediawiki.legacy/ajax.js194
-rw-r--r--resources/src/mediawiki.legacy/commonPrint.css44
-rw-r--r--resources/src/mediawiki.legacy/oldshared.css13
-rw-r--r--resources/src/mediawiki.legacy/protect.js3
-rw-r--r--resources/src/mediawiki.legacy/shared.css278
-rw-r--r--resources/src/mediawiki.legacy/wikibits.js38
-rw-r--r--resources/src/mediawiki.less/mediawiki.mixins.less4
-rw-r--r--resources/src/mediawiki.less/mediawiki.ui/mixins.less29
-rw-r--r--resources/src/mediawiki.less/mediawiki.ui/variables.less13
-rw-r--r--resources/src/mediawiki.messagePoster/mediawiki.messagePoster.factory.js14
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.gallery.css101
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.gallery.js37
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.gallery.print.css35
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.image.pagination.js9
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js8
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.ready.js11
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.startup.js11
-rw-r--r--resources/src/mediawiki.page/mediawiki.page.watch.ajax.js15
-rw-r--r--resources/src/mediawiki.skinning/content.css3
-rw-r--r--resources/src/mediawiki.skinning/elements.css13
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.changeemail.js1
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.changeslist.css4
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.changeslist.enhanced.css4
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.changeslist.legend.js33
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.css11
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.movePage.css8
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.movePage.js5
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.preferences.css17
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.preferences.js43
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.search.css1
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.search.js6
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.unwatchedPages.js4
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.upload.js79
-rw-r--r--resources/src/mediawiki.special/mediawiki.special.userlogin.common.js72
-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.html1
-rw-r--r--resources/src/mediawiki.toolbar/toolbar.js2
-rw-r--r--resources/src/mediawiki.ui/components/buttons.less16
-rw-r--r--resources/src/mediawiki.ui/components/checkbox.less3
-rw-r--r--resources/src/mediawiki.ui/components/icons.less33
-rw-r--r--resources/src/mediawiki.ui/components/images/ok.pngbin442 -> 0 bytes
-rw-r--r--resources/src/mediawiki.ui/components/images/ok.svg1
-rw-r--r--resources/src/mediawiki.widgets/AUTHORS.txt10
-rw-r--r--resources/src/mediawiki.widgets/LICENSE.txt25
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.js558
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.less243
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js189
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.CategorySelector.js378
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.base.css26
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.js118
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.base.css20
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.js63
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.js629
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.less134
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.NamespaceInputWidget.js69
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css57
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js341
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js82
-rw-r--r--resources/src/mediawiki.widgets/mw.widgets.UserInputWidget.js119
-rw-r--r--resources/src/mediawiki/images/feed-icon.png (renamed from resources/src/mediawiki.legacy/images/feed-icon.png)bin542 -> 542 bytes
-rw-r--r--resources/src/mediawiki/images/feed-icon.svg (renamed from resources/src/mediawiki.legacy/images/feed-icon.svg)0
-rw-r--r--resources/src/mediawiki/images/question.png (renamed from resources/src/mediawiki.legacy/images/question.png)bin316 -> 316 bytes
-rw-r--r--resources/src/mediawiki/images/question.svg (renamed from resources/src/mediawiki.legacy/images/question.svg)0
-rw-r--r--resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.css5
-rw-r--r--resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.js247
-rw-r--r--resources/src/mediawiki/mediawiki.ForeignStructuredUpload.js184
-rw-r--r--resources/src/mediawiki/mediawiki.ForeignUpload.js135
-rw-r--r--resources/src/mediawiki/mediawiki.RegExp.js22
-rw-r--r--resources/src/mediawiki/mediawiki.Title.js118
-rw-r--r--resources/src/mediawiki/mediawiki.Upload.BookletLayout.js543
-rw-r--r--resources/src/mediawiki/mediawiki.Upload.Dialog.js205
-rw-r--r--resources/src/mediawiki/mediawiki.Upload.js368
-rw-r--r--resources/src/mediawiki/mediawiki.Uri.js19
-rw-r--r--resources/src/mediawiki/mediawiki.Uri.loose.regexp22
-rw-r--r--resources/src/mediawiki/mediawiki.Uri.strict.regexp13
-rw-r--r--resources/src/mediawiki/mediawiki.apihelp.css4
-rw-r--r--resources/src/mediawiki/mediawiki.confirmCloseWindow.js68
-rw-r--r--resources/src/mediawiki/mediawiki.cookie.js6
-rw-r--r--resources/src/mediawiki/mediawiki.debug.js14
-rw-r--r--resources/src/mediawiki/mediawiki.errorLogger.js3
-rw-r--r--resources/src/mediawiki/mediawiki.experiments.js110
-rw-r--r--resources/src/mediawiki/mediawiki.feedback.js19
-rw-r--r--resources/src/mediawiki/mediawiki.feedlink.css16
-rw-r--r--resources/src/mediawiki/mediawiki.filewarning.less6
-rw-r--r--resources/src/mediawiki/mediawiki.htmlform.css51
-rw-r--r--resources/src/mediawiki/mediawiki.htmlform.js40
-rw-r--r--resources/src/mediawiki/mediawiki.htmlform.ooui.css31
-rw-r--r--resources/src/mediawiki/mediawiki.inspect.js39
-rw-r--r--resources/src/mediawiki/mediawiki.jqueryMsg.js363
-rw-r--r--resources/src/mediawiki/mediawiki.js923
-rw-r--r--resources/src/mediawiki/mediawiki.log.js1
-rw-r--r--resources/src/mediawiki/mediawiki.notification.common.css7
-rw-r--r--resources/src/mediawiki/mediawiki.notification.css15
-rw-r--r--resources/src/mediawiki/mediawiki.notification.js21
-rw-r--r--resources/src/mediawiki/mediawiki.notify.js5
-rw-r--r--resources/src/mediawiki/mediawiki.searchSuggest.js161
-rw-r--r--resources/src/mediawiki/mediawiki.startUp.js11
-rw-r--r--resources/src/mediawiki/mediawiki.storage.js58
-rw-r--r--resources/src/mediawiki/mediawiki.template.js8
-rw-r--r--resources/src/mediawiki/mediawiki.template.mustache.js2
-rw-r--r--resources/src/mediawiki/mediawiki.template.regexp.js15
-rw-r--r--resources/src/mediawiki/mediawiki.toc.js12
-rw-r--r--resources/src/mediawiki/mediawiki.user.js34
-rw-r--r--resources/src/mediawiki/mediawiki.userSuggest.js6
-rw-r--r--resources/src/mediawiki/mediawiki.util.js15
-rw-r--r--resources/src/moment-local-dmy.js16
-rw-r--r--resources/src/oojs-ui-local.css7
-rw-r--r--resources/src/polyfill-nodeTypes.js19
-rw-r--r--resources/src/startup.js73
1554 files changed, 33490 insertions, 15122 deletions
diff --git a/resources/Resources.php b/resources/Resources.php
index feda8a53..6a22af66 100644
--- a/resources/Resources.php
+++ b/resources/Resources.php
@@ -39,6 +39,7 @@ return array(
'group' => 'noscript',
),
'filepage' => array(
+ 'position' => 'top',
'class' => 'ResourceLoaderWikiModule',
'styles' => array( 'MediaWiki:Filepage.css' ),
),
@@ -90,19 +91,22 @@ return array(
* including more than one of them into your skin as this will result in duplicate CSS.
*/
'mediawiki.skinning.elements' => array(
+ 'position' => 'top',
'styles' => array(
'resources/src/mediawiki.skinning/elements.css' => array( 'media' => 'screen' ),
),
),
'mediawiki.skinning.content' => array(
+ 'position' => 'top',
'styles' => array(
'resources/src/mediawiki.skinning/elements.css' => array( 'media' => 'screen' ),
'resources/src/mediawiki.skinning/content.css' => array( 'media' => 'screen' ),
),
),
+ // Used in the web installer. Test it after modifying this definition!
'mediawiki.skinning.interface' => array(
+ 'position' => 'top',
'class' => 'ResourceLoaderSkinModule',
- // Used in the web installer. Test it after modifying this definition!
'styles' => array(
'resources/src/mediawiki.skinning/elements.css' => array( 'media' => 'screen' ),
'resources/src/mediawiki.skinning/content.css' => array( 'media' => 'screen' ),
@@ -111,6 +115,7 @@ return array(
),
'mediawiki.skinning.content.parsoid' => array(
+ 'position' => 'top',
// Style Parsoid HTML+RDFa output consistent with wikitext from PHP parser
// with the interface.css styles; skinStyles should be used if your
// skin over-rides common content styling.
@@ -121,6 +126,7 @@ return array(
),
'mediawiki.skinning.content.externallinks' => array(
+ 'position' => 'bottom',
'styles' => array(
'resources/src/mediawiki.skinning/content.externallinks.css' => array( 'media' => 'screen' ),
),
@@ -142,7 +148,7 @@ return array(
'scripts' => 'resources/src/jquery/jquery.accessKeyLabel.js',
'dependencies' => array(
'jquery.client',
- 'jquery.mwExtension',
+ 'mediawiki.RegExp',
),
'messages' => array( 'brackets', 'word-separator' ),
'targets' => array( 'mobile', 'desktop' ),
@@ -209,7 +215,6 @@ return array(
'styles' => 'resources/src/jquery/jquery.confirmable.css',
'dependencies' => 'mediawiki.jqueryMsg',
),
- // Use mediawiki.cookie in new code, rather than jquery.cookie.
'jquery.cookie' => array(
'scripts' => 'resources/lib/jquery/jquery.cookie.js',
'targets' => array( 'desktop', 'mobile' ),
@@ -242,12 +247,44 @@ return array(
),
'jquery.highlightText' => array(
'scripts' => 'resources/src/jquery/jquery.highlightText.js',
- 'dependencies' => 'jquery.mwExtension',
+ 'dependencies' => array(
+ 'mediawiki.RegExp',
+ 'dom-level2-shim',
+ ),
'targets' => array( 'desktop', 'mobile' ),
),
'jquery.hoverIntent' => array(
'scripts' => 'resources/lib/jquery/jquery.hoverIntent.js',
),
+ 'jquery.i18n' => array(
+ 'scripts' => array(
+ 'resources/lib/jquery.i18n/src/jquery.i18n.js',
+ 'resources/lib/jquery.i18n/src/jquery.i18n.messagestore.js',
+ 'resources/lib/jquery.i18n/src/jquery.i18n.parser.js',
+ 'resources/lib/jquery.i18n/src/jquery.i18n.emitter.js',
+ 'resources/lib/jquery.i18n/src/jquery.i18n.emitter.bidi.js',
+ 'resources/lib/jquery.i18n/src/jquery.i18n.language.js',
+ 'resources/lib/jquery.i18n/src/jquery.i18n.fallbacks.js',
+ ),
+ 'dependencies' => 'mediawiki.libs.pluralruleparser',
+ 'languageScripts' => array(
+ 'bs' => 'resources/lib/jquery.i18n/src/languages/bs.js',
+ 'dsb' => 'resources/lib/jquery.i18n/src/languages/dsb.js',
+ 'fi' => 'resources/lib/jquery.i18n/src/languages/fi.js',
+ 'ga' => 'resources/lib/jquery.i18n/src/languages/ga.js',
+ 'he' => 'resources/lib/jquery.i18n/src/languages/he.js',
+ 'hsb' => 'resources/lib/jquery.i18n/src/languages/hsb.js',
+ 'hu' => 'resources/lib/jquery.i18n/src/languages/hu.js',
+ 'hy' => 'resources/lib/jquery.i18n/src/languages/hy.js',
+ 'la' => 'resources/lib/jquery.i18n/src/languages/la.js',
+ 'ml' => 'resources/lib/jquery.i18n/src/languages/ml.js',
+ 'os' => 'resources/lib/jquery.i18n/src/languages/os.js',
+ 'ru' => 'resources/lib/jquery.i18n/src/languages/ru.js',
+ 'sl' => 'resources/lib/jquery.i18n/src/languages/sl.js',
+ 'uk' => 'resources/lib/jquery.i18n/src/languages/uk.js',
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
'jquery.localize' => array(
'scripts' => 'resources/src/jquery/jquery.localize.js',
),
@@ -304,13 +341,15 @@ return array(
'styles' => 'resources/src/jquery/jquery.tablesorter.css',
'messages' => array( 'sort-descending', 'sort-ascending' ),
'dependencies' => array(
- 'jquery.mwExtension',
+ 'dom-level2-shim',
+ 'mediawiki.RegExp',
'mediawiki.language.months',
),
),
'jquery.textSelection' => array(
'scripts' => 'resources/src/jquery/jquery.textSelection.js',
'dependencies' => 'jquery.client',
+ 'targets' => array( 'mobile', 'desktop' ),
),
'jquery.throttle-debounce' => array(
'scripts' => 'resources/lib/jquery/jquery.ba-throttle-debounce.js',
@@ -334,6 +373,13 @@ return array(
'jquery.ui.core' => array(
'scripts' => 'resources/lib/jquery.ui/jquery.ui.core.js',
+ 'dependencies' => array(
+ 'jquery.ui.core.styles',
+ ),
+ 'group' => 'jquery.ui',
+ ),
+ 'jquery.ui.core.styles' => array(
+ 'position' => 'top',
'skinStyles' => array(
'default' => array(
'resources/lib/jquery.ui/themes/smoothness/jquery.ui.core.css',
@@ -687,7 +733,10 @@ return array(
/* Moment.js */
'moment' => array(
- 'scripts' => 'resources/lib/moment/moment.js',
+ 'scripts' => array(
+ 'resources/lib/moment/moment.js',
+ 'resources/src/moment-local-dmy.js',
+ ),
'languageScripts' => array(
'af' => 'resources/lib/moment/locale/af.js',
'ar' => 'resources/lib/moment/locale/ar.js',
@@ -772,14 +821,14 @@ return array(
/* MediaWiki */
'mediawiki' => array(
- // Keep maintenance/jsduck/eg-iframe.html in sync
+ 'class' => 'ResourceLoaderRawFileModule',
+ // Keep in sync with maintenance/jsduck/eg-iframe.html
'scripts' => array(
+ 'resources/lib/phpjs-sha1/sha1.js',
'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(
@@ -798,6 +847,12 @@ return array(
'resources/src/mediawiki/mediawiki.template.mustache.js',
),
'targets' => array( 'desktop', 'mobile' ),
+ 'dependencies' => 'mediawiki.template',
+ ),
+ 'mediawiki.template.regexp' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.template.regexp.js',
+ 'targets' => array( 'desktop', 'mobile' ),
+ 'dependencies' => 'mediawiki.template',
),
'mediawiki.apipretty' => array(
'styles' => 'resources/src/mediawiki/mediawiki.apipretty.css',
@@ -806,7 +861,10 @@ return array(
),
'mediawiki.api' => array(
'scripts' => 'resources/src/mediawiki.api/mediawiki.api.js',
- 'dependencies' => 'mediawiki.util',
+ 'dependencies' => array(
+ 'mediawiki.util',
+ 'user.tokens',
+ ),
'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.api.category' => array(
@@ -821,7 +879,6 @@ return array(
'dependencies' => array(
'mediawiki.api',
'mediawiki.Title',
- 'user.tokens',
),
'targets' => array( 'desktop', 'mobile' ),
),
@@ -837,15 +894,25 @@ return array(
'mediawiki.api.parse' => array(
'scripts' => 'resources/src/mediawiki.api/mediawiki.api.parse.js',
'dependencies' => 'mediawiki.api',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+ 'mediawiki.api.upload' => array(
+ 'scripts' => 'resources/src/mediawiki.api/mediawiki.api.upload.js',
+ 'dependencies' => array(
+ 'dom-level2-shim',
+ 'mediawiki.api',
+ 'mediawiki.api.edit',
+ 'json',
+ ),
),
'mediawiki.api.watch' => array(
'scripts' => 'resources/src/mediawiki.api/mediawiki.api.watch.js',
'dependencies' => array(
'mediawiki.api',
- 'user.tokens',
),
),
'mediawiki.content.json' => array(
+ 'position' => 'top',
'styles' => 'resources/src/mediawiki/mediawiki.content.json.css',
),
'mediawiki.confirmCloseWindow' => array(
@@ -908,7 +975,10 @@ return array(
'feedback-useragent'
),
),
-
+ 'mediawiki.feedlink' => array(
+ 'position' => 'top',
+ 'styles' => 'resources/src/mediawiki/mediawiki.feedlink.css',
+ ),
'mediawiki.filewarning' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.filewarning.js',
'styles' => 'resources/src/mediawiki/mediawiki.filewarning.less',
@@ -916,8 +986,22 @@ return array(
'oojs-ui',
),
),
-
+ 'mediawiki.ForeignApi' => array(
+ 'targets' => array( 'desktop', 'mobile' ),
+ 'class' => 'ResourceLoaderForeignApiModule',
+ // Additional dependencies generated dynamically
+ 'dependencies' => 'mediawiki.ForeignApi.core',
+ ),
+ 'mediawiki.ForeignApi.core' => array(
+ 'scripts' => 'resources/src/mediawiki.api/mediawiki.ForeignApi.js',
+ 'dependencies' => array(
+ 'mediawiki.api',
+ 'oojs',
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
'mediawiki.helplink' => array(
+ 'position' => 'top',
'styles' => array(
'resources/src/mediawiki/mediawiki.helplink.less',
),
@@ -937,7 +1021,7 @@ return array(
'mediawiki.htmlform' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.htmlform.js',
'dependencies' => array(
- 'jquery.mwExtension',
+ 'mediawiki.RegExp',
'jquery.byteLimit',
),
'messages' => array(
@@ -946,6 +1030,14 @@ return array(
'colon-separator',
),
),
+ 'mediawiki.htmlform.styles' => array(
+ 'styles' => 'resources/src/mediawiki/mediawiki.htmlform.css',
+ 'position' => 'top',
+ ),
+ 'mediawiki.htmlform.ooui.styles' => array(
+ 'styles' => 'resources/src/mediawiki/mediawiki.htmlform.ooui.css',
+ 'position' => 'top',
+ ),
'mediawiki.icon' => array(
'styles' => 'resources/src/mediawiki/mediawiki.icon.less',
),
@@ -953,6 +1045,7 @@ return array(
'scripts' => 'resources/src/mediawiki/mediawiki.inspect.js',
'dependencies' => array(
'jquery.byteLength',
+ 'mediawiki.RegExp',
'json',
),
'targets' => array( 'desktop', 'mobile' ),
@@ -980,10 +1073,13 @@ return array(
),
'mediawiki.notification' => array(
'styles' => array(
- 'resources/src/mediawiki/mediawiki.notification.css',
+ 'resources/src/mediawiki/mediawiki.notification.common.css',
'resources/src/mediawiki/mediawiki.notification.hideForPrint.css'
=> array( 'media' => 'print' ),
),
+ 'skinStyles' => array(
+ 'default' => 'resources/src/mediawiki/mediawiki.notification.css',
+ ),
'scripts' => 'resources/src/mediawiki/mediawiki.notification.js',
'dependencies' => 'mediawiki.page.startup',
'targets' => array( 'desktop', 'mobile' ),
@@ -992,6 +1088,10 @@ return array(
'scripts' => 'resources/src/mediawiki/mediawiki.notify.js',
'targets' => array( 'desktop', 'mobile' ),
),
+ 'mediawiki.RegExp' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.RegExp.js',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
'mediawiki.pager.tablePager' => array(
'styles' => 'resources/src/mediawiki/mediawiki.pager.tablePager.less',
'position' => 'top',
@@ -1012,10 +1112,15 @@ return array(
),
),
'mediawiki.sectionAnchor' => array(
+ 'position' => 'top',
// 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.storage' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.storage.js',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
'mediawiki.Title' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.Title.js',
'dependencies' => array(
@@ -1024,21 +1129,157 @@ return array(
),
'targets' => array( 'desktop', 'mobile' ),
),
+ 'mediawiki.Upload' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.Upload.js',
+ 'dependencies' => array(
+ 'dom-level2-shim',
+ 'mediawiki.api.upload',
+ ),
+ ),
+ 'mediawiki.ForeignUpload' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.ForeignUpload.js',
+ 'dependencies' => array(
+ 'mediawiki.ForeignApi',
+ 'mediawiki.Upload',
+ 'oojs',
+ ),
+ ),
+ 'mediawiki.ForeignStructuredUpload' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.ForeignStructuredUpload.js',
+ 'dependencies' => array(
+ 'mediawiki.ForeignUpload',
+ ),
+ ),
+ 'mediawiki.Upload.Dialog' => array(
+ 'scripts' => array(
+ 'resources/src/mediawiki/mediawiki.Upload.Dialog.js',
+ ),
+ 'dependencies' => array(
+ 'mediawiki.Upload.BookletLayout',
+ ),
+ 'messages' => array(
+ 'upload-dialog-title',
+ 'upload-dialog-button-cancel',
+ 'upload-dialog-button-done',
+ 'upload-dialog-button-save',
+ 'upload-dialog-button-upload',
+ ),
+ ),
+ 'mediawiki.Upload.BookletLayout' => array(
+ 'scripts' => array(
+ 'resources/src/mediawiki/mediawiki.Upload.BookletLayout.js',
+ ),
+ 'dependencies' => array(
+ 'oojs-ui',
+ 'mediawiki.Upload',
+ 'mediawiki.jqueryMsg',
+ ),
+ 'messages' => array(
+ 'upload-form-label-select-file',
+ 'upload-form-label-infoform-title',
+ 'upload-form-label-infoform-name',
+ 'upload-form-label-infoform-description',
+ 'upload-form-label-usage-title',
+ 'upload-form-label-usage-filename',
+ 'api-error-unknownerror',
+ 'api-error-unknown-warning',
+ 'api-error-badaccess-groups',
+ 'api-error-badtoken',
+ 'api-error-copyuploaddisabled',
+ 'api-error-duplicate',
+ 'api-error-duplicate-archive',
+ 'api-error-empty-file',
+ 'api-error-emptypage',
+ 'api-error-fetchfileerror',
+ 'api-error-fileexists-forbidden',
+ 'api-error-fileexists-shared-forbidden',
+ 'api-error-file-too-large',
+ 'api-error-filename-tooshort',
+ 'api-error-filetype-banned',
+ 'api-error-filetype-banned-type',
+ 'api-error-filetype-missing',
+ 'api-error-hookaborted',
+ 'api-error-http',
+ 'api-error-illegal-filename',
+ 'api-error-internal-error',
+ 'api-error-invalid-file-key',
+ 'api-error-missingparam',
+ 'api-error-missingresult',
+ 'api-error-mustbeloggedin',
+ 'api-error-mustbeposted',
+ 'api-error-noimageinfo',
+ 'api-error-nomodule',
+ 'api-error-ok-but-empty',
+ 'api-error-overwrite',
+ 'api-error-stashfailed',
+ 'api-error-publishfailed',
+ 'api-error-stasherror',
+ 'api-error-stashedfilenotfound',
+ 'api-error-stashpathinvalid',
+ 'api-error-stashfilestorage',
+ 'api-error-stashzerolength',
+ 'api-error-stashnotloggedin',
+ 'api-error-stashwrongowner',
+ 'api-error-stashnosuchfilekey',
+ 'api-error-timeout',
+ 'api-error-unclassified',
+ 'api-error-unknown-code',
+ 'api-error-unknown-error',
+ 'api-error-uploaddisabled',
+ 'api-error-verification-error',
+ 'fileexists',
+ 'filepageexists',
+ 'filename-bad-prefix',
+ 'filename-thumb-name',
+ 'badfilename',
+ 'api-error-duplicate-archive',
+ 'api-error-blacklisted', // HACK
+ ),
+ ),
+ 'mediawiki.ForeignStructuredUpload.BookletLayout' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.js',
+ 'styles' => 'resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.css',
+ 'dependencies' => array(
+ 'mediawiki.ForeignStructuredUpload',
+ 'mediawiki.Upload.BookletLayout',
+ 'mediawiki.widgets.CategorySelector',
+ 'mediawiki.widgets.DateInputWidget',
+ 'mediawiki.jqueryMsg',
+ ),
+ 'messages' => array(
+ 'foreign-structured-upload-form-label-own-work',
+ 'foreign-structured-upload-form-label-infoform-categories',
+ 'foreign-structured-upload-form-label-infoform-date',
+ 'foreign-structured-upload-form-label-own-work-message-default',
+ 'foreign-structured-upload-form-label-not-own-work-message-default',
+ 'foreign-structured-upload-form-label-not-own-work-local-default',
+ 'foreign-structured-upload-form-label-own-work-message-shared',
+ 'foreign-structured-upload-form-label-not-own-work-message-shared',
+ 'foreign-structured-upload-form-label-not-own-work-local-shared',
+ 'foreign-structured-upload-form-label-own-work-message-local',
+ 'foreign-structured-upload-form-label-not-own-work-message-local',
+ 'foreign-structured-upload-form-label-not-own-work-local-local',
+ ),
+ ),
'mediawiki.toc' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.toc.js',
- 'dependencies' => 'jquery.cookie',
+ 'dependencies' => 'mediawiki.cookie',
'messages' => array( 'showtoc', 'hidetoc' ),
'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.Uri' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.Uri.js',
+ 'templates' => array(
+ 'strict.regexp' => 'resources/src/mediawiki/mediawiki.Uri.strict.regexp',
+ 'loose.regexp' => 'resources/src/mediawiki/mediawiki.Uri.loose.regexp',
+ ),
'dependencies' => 'mediawiki.util',
'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.user' => array(
'scripts' => 'resources/src/mediawiki/mediawiki.user.js',
'dependencies' => array(
- 'jquery.cookie',
+ 'mediawiki.cookie',
'mediawiki.api',
'user.options',
'user.tokens',
@@ -1056,7 +1297,7 @@ return array(
'scripts' => 'resources/src/mediawiki/mediawiki.util.js',
'dependencies' => array(
'jquery.accessKeyLabel',
- 'jquery.mwExtension',
+ 'mediawiki.RegExp',
'mediawiki.notify',
),
'position' => 'top', // For $wgPreloadJavaScriptMwUtil
@@ -1073,6 +1314,10 @@ return array(
'styles' => 'resources/src/mediawiki.toolbar/toolbar.less',
'position' => 'top',
),
+ 'mediawiki.experiments' => array(
+ 'scripts' => 'resources/src/mediawiki/mediawiki.experiments.js',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
/* MediaWiki Action */
@@ -1087,15 +1332,15 @@ return array(
'position' => 'top',
),
'mediawiki.action.edit.styles' => array(
- 'styles' => 'resources/src/mediawiki.action/mediawiki.action.edit.styles.css',
'position' => 'top',
+ 'styles' => 'resources/src/mediawiki.action/mediawiki.action.edit.styles.css',
),
'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',
'dependencies' => array(
'jquery.makeCollapsible',
- 'jquery.cookie',
+ 'mediawiki.cookie',
'mediawiki.icon',
),
),
@@ -1134,18 +1379,18 @@ return array(
),
),
'mediawiki.action.history' => array(
+ 'position' => 'top',
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.history.js',
'styles' => 'resources/src/mediawiki.action/mediawiki.action.history.css',
- 'group' => 'mediawiki.action.history',
),
'mediawiki.action.history.diff' => array(
+ 'position' => 'top',
'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' ),
),
'mediawiki.action.view.dblClickEdit' => array(
@@ -1165,6 +1410,7 @@ return array(
),
),
'mediawiki.action.view.categoryPage.styles' => array(
+ 'position' => 'top',
'styles' => 'resources/src/mediawiki.action/mediawiki.action.view.categoryPage.less',
'targets' => array( 'desktop', 'mobile' )
),
@@ -1190,8 +1436,8 @@ return array(
'position' => 'top',
),
'mediawiki.action.view.redirectPage' => array(
- 'styles' => 'resources/src/mediawiki.action/mediawiki.action.view.redirectPage.css',
'position' => 'top',
+ 'styles' => 'resources/src/mediawiki.action/mediawiki.action.view.redirectPage.css',
),
'mediawiki.action.view.rightClickEdit' => array(
'scripts' => 'resources/src/mediawiki.action/mediawiki.action.view.rightClickEdit.js',
@@ -1210,6 +1456,13 @@ return array(
'prefs-editing'
),
),
+ 'mediawiki.action.view.filepage' => array(
+ 'styles' => array(
+ 'resources/src/mediawiki.action/mediawiki.action.view.filepage.print.css' => array( 'media' => 'print' ),
+ 'resources/src/mediawiki.action/mediawiki.action.view.filepage.css',
+ ),
+ 'position' => 'top',
+ ),
/* MediaWiki Language */
@@ -1265,10 +1518,14 @@ return array(
),
'mediawiki.jqueryMsg' => array(
+ // Add data for mediawiki.jqueryMsg, such as allowed tags
+ 'class' => 'ResourceLoaderJqueryMsgModule',
'scripts' => 'resources/src/mediawiki/mediawiki.jqueryMsg.js',
'dependencies' => array(
'mediawiki.util',
'mediawiki.language',
+ 'user.options',
+ 'dom-level2-shim',
),
'targets' => array( 'desktop', 'mobile' ),
),
@@ -1300,9 +1557,18 @@ return array(
'mediawiki.page.gallery' => array(
'scripts' => 'resources/src/mediawiki.page/mediawiki.page.gallery.js',
'dependencies' => array(
+ 'mediawiki.page.gallery.styles',
'jquery.throttle-debounce',
)
),
+ 'mediawiki.page.gallery.styles' => array(
+ 'styles' => array(
+ 'resources/src/mediawiki.page/mediawiki.page.gallery.print.css' => array( 'media' => 'print' ),
+ 'resources/src/mediawiki.page/mediawiki.page.gallery.css',
+ ),
+ 'position' => 'top',
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
'mediawiki.page.ready' => array(
'scripts' => 'resources/src/mediawiki.page/mediawiki.page.ready.js',
'dependencies' => array(
@@ -1345,7 +1611,7 @@ return array(
'mediawiki.page.startup',
'mediawiki.util',
'jquery.accessKeyLabel',
- 'jquery.mwExtension',
+ 'mediawiki.RegExp',
),
'messages' => array(
'watch',
@@ -1369,6 +1635,7 @@ return array(
/* MediaWiki Special pages */
'mediawiki.special' => array(
+ 'position' => 'top',
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.js',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.css',
),
@@ -1387,19 +1654,22 @@ return array(
),
),
'mediawiki.special.changeslist' => array(
+ 'position' => 'top',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.changeslist.css',
),
'mediawiki.special.changeslist.legend' => array(
+ 'position' => 'top',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.changeslist.legend.css',
),
'mediawiki.special.changeslist.legend.js' => array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.changeslist.legend.js',
'dependencies' => array(
'jquery.makeCollapsible',
- 'jquery.cookie',
+ 'mediawiki.cookie',
),
),
'mediawiki.special.changeslist.enhanced' => array(
+ 'position' => 'top',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.changeslist.enhanced.css',
),
'mediawiki.special.edittags' => array(
@@ -1421,12 +1691,20 @@ return array(
),
'mediawiki.special.movePage' => array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.movePage.js',
- 'dependencies' => 'jquery.byteLimit',
+ 'dependencies' => array(
+ 'jquery.byteLimit',
+ 'mediawiki.widgets',
+ ),
+ ),
+ 'mediawiki.special.movePage.styles' => array(
+ 'styles' => 'resources/src/mediawiki.special/mediawiki.special.movePage.css',
+ 'position' => 'top',
),
'mediawiki.special.pageLanguage' => array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.pageLanguage.js',
),
'mediawiki.special.pagesWithProp' => array(
+ 'position' => 'top',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.pagesWithProp.css',
),
'mediawiki.special.preferences' => array(
@@ -1437,10 +1715,12 @@ return array(
'prefs-tabs-navigation-hint',
'prefswarning-warning',
'saveprefs',
+ 'savedprefs',
),
'dependencies' => array(
'mediawiki.language',
'mediawiki.confirmCloseWindow',
+ 'mediawiki.notification',
),
),
'mediawiki.special.recentchanges' => array(
@@ -1449,6 +1729,7 @@ return array(
'position' => 'top',
),
'mediawiki.special.search' => array(
+ 'position' => 'top',
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.search.js',
'styles' => 'resources/src/mediawiki.special/mediawiki.special.search.css',
'messages' => array(
@@ -1494,25 +1775,16 @@ return array(
'position' => 'top',
),
'mediawiki.special.userlogin.signup.styles' => array(
+ 'position' => 'top',
'styles' => array(
'resources/src/mediawiki.special/mediawiki.special.userlogin.signup.css',
),
- 'position' => 'top',
),
'mediawiki.special.userlogin.login.styles' => array(
+ 'position' => 'top',
'styles' => array(
'resources/src/mediawiki.special/mediawiki.special.userlogin.login.css',
),
- 'position' => 'top',
- ),
- 'mediawiki.special.userlogin.common.js' => array(
- 'scripts' => array(
- 'resources/src/mediawiki.special/mediawiki.special.userlogin.common.js',
- ),
- 'messages' => array(
- 'createacct-captcha',
- 'createacct-imgcaptcha-ph',
- ),
),
'mediawiki.special.userlogin.signup.js' => array(
'scripts' => 'resources/src/mediawiki.special/mediawiki.special.userlogin.signup.js',
@@ -1564,8 +1836,8 @@ return array(
/* MediaWiki Installer */
+ // Used in the web installer. Test it after modifying this definition!
'mediawiki.legacy.config' => array(
- // Used in the web installer. Test it after modifying this definition!
// These files are not actually loaded via ResourceLoader, so dependencies etc. won't work.
'scripts' => 'mw-config/config.js',
'styles' => 'mw-config/config.css',
@@ -1573,15 +1845,8 @@ return array(
/* MediaWiki Legacy */
- 'mediawiki.legacy.ajax' => array(
- 'scripts' => 'resources/src/mediawiki.legacy/ajax.js',
- 'dependencies' => array(
- 'mediawiki.util',
- 'mediawiki.legacy.wikibits',
- ),
- 'position' => 'top',
- ),
'mediawiki.legacy.commonPrint' => array(
+ 'position' => 'top',
'styles' => array(
'resources/src/mediawiki.legacy/commonPrint.css' => array( 'media' => 'print' )
),
@@ -1591,13 +1856,15 @@ return array(
'dependencies' => 'jquery.byteLimit',
'messages' => array( 'protect-unchain-permissions' )
),
+ // Used in the web installer. Test it after modifying this definition!
'mediawiki.legacy.shared' => array(
- // Used in the web installer. Test it after modifying this definition!
+ 'position' => 'top',
'styles' => array(
'resources/src/mediawiki.legacy/shared.css' => array( 'media' => 'screen' )
),
),
'mediawiki.legacy.oldshared' => array(
+ 'position' => 'top',
'styles' => array(
'resources/src/mediawiki.legacy/oldshared.css' => array( 'media' => 'screen' )
),
@@ -1606,85 +1873,175 @@ return array(
'scripts' => 'resources/src/mediawiki.legacy/wikibits.js',
'dependencies' => 'mediawiki.util',
'position' => 'top',
+ 'targets' => array( 'desktop', 'mobile' ),
),
/* MediaWiki UI */
'mediawiki.ui' => array(
+ 'position' => 'top',
'skinStyles' => array(
'default' => array(
'resources/src/mediawiki.ui/default.less',
),
),
- 'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.ui.checkbox' => array(
+ 'position' => 'top',
'skinStyles' => array(
'default' => array(
'resources/src/mediawiki.ui/components/checkbox.less',
),
),
- 'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.ui.radio' => array(
+ 'position' => 'top',
'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(
+ 'position' => 'top',
'skinStyles' => array(
'default' => array(
'resources/src/mediawiki.ui/components/anchors.less',
),
),
- 'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
// Lightweight module for button styles
'mediawiki.ui.button' => array(
+ 'position' => 'top',
'skinStyles' => array(
'default' => array(
'resources/src/mediawiki.ui/components/buttons.less',
),
),
- 'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.ui.input' => array(
+ 'position' => 'top',
'skinStyles' => array(
'default' => array(
'resources/src/mediawiki.ui/components/inputs.less',
),
),
- 'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
'mediawiki.ui.icon' => array(
+ 'position' => 'top',
'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(
+ 'position' => 'top',
'skinStyles' => array(
'default' => array(
'resources/src/mediawiki.ui/components/text.less',
),
),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+
+ 'mediawiki.widgets' => array(
+ 'scripts' => array(
+ 'resources/src/mediawiki.widgets/mw.widgets.NamespaceInputWidget.js',
+ 'resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.js',
+ 'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js',
+ 'resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.js',
+ 'resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js',
+ ),
+ 'skinStyles' => array(
+ 'default' => array(
+ 'resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css',
+ ),
+ ),
+ 'dependencies' => array(
+ 'oojs-ui',
+ 'mediawiki.widgets.styles',
+ // TitleInputWidget
+ 'mediawiki.Title',
+ 'mediawiki.api',
+ 'jquery.byteLimit',
+ // TitleOptionWidget
+ 'jquery.autoEllipsis',
+ // CategorySelector
+ 'mediawiki.ForeignApi',
+ // FIXME: Kept for bc
+ 'mediawiki.widgets.CategorySelector',
+ ),
+ 'messages' => array(
+ // NamespaceInputWidget
+ 'blanknamespace',
+ 'namespacesall',
+ // TitleInputWidget
+ 'mw-widgets-titleinput-description-new-page',
+ 'mw-widgets-titleinput-description-redirect',
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+ 'mediawiki.widgets.styles' => array(
+ 'skinStyles' => array(
+ 'default' => array(
+ 'resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.base.css',
+ 'resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.base.css',
+ ),
+ ),
'position' => 'top',
'targets' => array( 'desktop', 'mobile' ),
),
+ 'mediawiki.widgets.DateInputWidget' => array(
+ 'scripts' => array(
+ 'resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.js',
+ 'resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.js',
+ ),
+ 'skinStyles' => array(
+ 'default' => array(
+ 'resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.less',
+ 'resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.less',
+ ),
+ ),
+ 'messages' => array(
+ 'mw-widgets-dateinput-no-date',
+ 'mw-widgets-dateinput-placeholder-day',
+ 'mw-widgets-dateinput-placeholder-month',
+ ),
+ 'dependencies' => array(
+ 'oojs-ui',
+ 'moment',
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+ 'mediawiki.widgets.CategorySelector' => array(
+ 'scripts' => array(
+ 'resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js',
+ 'resources/src/mediawiki.widgets/mw.widgets.CategorySelector.js',
+ ),
+ 'dependencies' => array(
+ 'oojs-ui',
+ 'mediawiki.api',
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ ),
+ 'mediawiki.widgets.UserInputWidget' => array(
+ 'scripts' => array(
+ 'resources/src/mediawiki.widgets/mw.widgets.UserInputWidget.js',
+ ),
+ 'dependencies' => array(
+ 'oojs-ui',
+ ),
+ ),
/* es5-shim */
'es5-shim' => array(
@@ -1696,6 +2053,14 @@ return array(
'skipFunction' => 'resources/src/es5-skip.js',
),
+ /* dom-level2-shim */
+ // IE 8
+ 'dom-level2-shim' => array(
+ 'scripts' => 'resources/src/polyfill-nodeTypes.js',
+ 'targets' => array( 'desktop', 'mobile' ),
+ 'skipFunction' => 'resources/src/dom-level2-skip.js',
+ ),
+
/* OOjs */
'oojs' => array(
'scripts' => array(
@@ -1711,41 +2076,5 @@ return array(
/* OOjs UI */
// WARNING: OOjs-UI is NOT TESTED with older browsers and is likely to break
// if loaded in browsers that don't support ES5
- 'oojs-ui' => array(
- 'scripts' => array(
- 'resources/lib/oojs-ui/oojs-ui.js',
- ),
- 'skinScripts' => array(
- 'default' => 'resources/lib/oojs-ui/oojs-ui-mediawiki.js',
- ),
- 'dependencies' => array(
- 'es5-shim',
- 'oojs',
- 'oojs-ui.styles',
- ),
- 'messages' => array(
- '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',
- ),
- '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' ),
- ),
-
+ // @see ResourcesOOUI.php
);
diff --git a/resources/ResourcesOOUI.php b/resources/ResourcesOOUI.php
new file mode 100644
index 00000000..caf6dabd
--- /dev/null
+++ b/resources/ResourcesOOUI.php
@@ -0,0 +1,132 @@
+<?php
+/**
+ * Definition of OOjs UI ResourceLoader modules.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * http://www.gnu.org/copyleft/gpl.html
+ *
+ * @file
+ */
+
+if ( !defined( 'MEDIAWIKI' ) ) {
+ die( 'Not an entry point.' );
+}
+
+// WARNING: OOjs-UI is NOT TESTED with older browsers and is likely to break
+// if loaded in browsers that don't support ES5
+return call_user_func( function () {
+ $themes = ExtensionRegistry::getInstance()->getAttribute( 'SkinOOUIThemes' );
+ // We only use the theme names for file names, and they are lowercase
+ $themes = array_map( 'strtolower', $themes );
+ $themes['default'] = 'mediawiki';
+
+ $modules = array();
+ $modules['oojs-ui'] = array(
+ 'scripts' => array(
+ 'resources/lib/oojs-ui/oojs-ui.js',
+ ),
+ 'skinScripts' => array_combine(
+ array_keys( $themes ),
+ array_map( function ( $theme ) {
+ // TODO Allow extensions to specify this path somehow
+ return "resources/lib/oojs-ui/oojs-ui-$theme.js";
+ }, array_values( $themes ) )
+ ),
+ 'dependencies' => array(
+ 'es5-shim',
+ 'oojs',
+ 'oojs-ui.styles',
+ 'oojs-ui.styles.icons',
+ 'oojs-ui.styles.indicators',
+ 'oojs-ui.styles.textures',
+ ),
+ 'messages' => array(
+ '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-selectfile-button-select',
+ 'ooui-selectfile-dragdrop-placeholder',
+ 'ooui-selectfile-not-supported',
+ 'ooui-selectfile-placeholder',
+ 'ooui-toolbar-more',
+ 'ooui-toolgroup-collapse',
+ 'ooui-toolgroup-expand',
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ );
+ $modules['oojs-ui.styles'] = array(
+ 'position' => 'top',
+ 'styles' => 'resources/src/oojs-ui-local.css', // HACK, see inside the file
+ 'skinStyles' => array_combine(
+ array_keys( $themes ),
+ array_map( function ( $theme ) {
+ // TODO Allow extensions to specify this path somehow
+ return "resources/lib/oojs-ui/oojs-ui-$theme-noimages.css";
+ }, array_values( $themes ) )
+ ),
+ 'targets' => array( 'desktop', 'mobile' ),
+ );
+
+ $imageSets = array(
+ // Comments for greppability
+ 'icons', // oojs-ui.styles.icons
+ 'indicators', // oojs-ui.styles.indicators
+ 'textures', // oojs-ui.styles.textures
+ 'icons-accessibility', // oojs-ui.styles.icons-accessibility
+ 'icons-alerts', // oojs-ui.styles.icons-alerts
+ 'icons-content', // oojs-ui.styles.icons-content
+ 'icons-editing-advanced', // oojs-ui.styles.icons-editing-advanced
+ 'icons-editing-core', // oojs-ui.styles.icons-editing-core
+ 'icons-editing-list', // oojs-ui.styles.icons-editing-list
+ 'icons-editing-styling', // oojs-ui.styles.icons-editing-styling
+ 'icons-interactions', // oojs-ui.styles.icons-interactions
+ 'icons-layout', // oojs-ui.styles.icons-layout
+ 'icons-location', // oojs-ui.styles.icons-location
+ 'icons-media', // oojs-ui.styles.icons-media
+ 'icons-moderation', // oojs-ui.styles.icons-moderation
+ 'icons-movement', // oojs-ui.styles.icons-movement
+ 'icons-user', // oojs-ui.styles.icons-user
+ 'icons-wikimedia', // oojs-ui.styles.icons-wikimedia
+ );
+ $rootPath = 'resources/lib/oojs-ui/themes';
+
+ foreach ( $imageSets as $name ) {
+ $module = array(
+ 'position' => 'top',
+ 'class' => 'ResourceLoaderOOUIImageModule',
+ 'name' => $name,
+ 'rootPath' => $rootPath,
+ );
+
+ if ( substr( $name, 0, 5 ) === 'icons' ) {
+ $module['selectorWithoutVariant'] = '.oo-ui-icon-{name}, .mw-ui-icon-{name}:before';
+ $module['selectorWithVariant'] = '
+ .oo-ui-image-{variant}.oo-ui-icon-{name}, .mw-ui-icon-{name}-{variant}:before,
+ /* Hack for Flow, see T110051 */
+ .mw-ui-hovericon:hover .mw-ui-icon-{name}-{variant}-hover:before,
+ .mw-ui-hovericon.mw-ui-icon-{name}-{variant}-hover:hover:before';
+ }
+
+ $modules["oojs-ui.styles.$name"] = $module;
+ }
+
+ return $modules;
+} );
diff --git a/resources/lib/es5-shim/es5-shim.js b/resources/lib/es5-shim/es5-shim.js
index 45959940..85f51e2d 100644
--- a/resources/lib/es5-shim/es5-shim.js
+++ b/resources/lib/es5-shim/es5-shim.js
@@ -1,17 +1,20 @@
/*!
* https://github.com/es-shims/es5-shim
- * @license es5-shim Copyright 2009-2014 by contributors, MIT License
+ * @license es5-shim Copyright 2009-2015 by contributors, MIT License
* see https://github.com/es-shims/es5-shim/blob/master/LICENSE
*/
// vim: ts=4 sts=4 sw=4 expandtab
-//Add semicolon to prevent IIFE from being passed as argument to concated code.
+// Add semicolon to prevent IIFE from being passed as argument to concatenated code.
;
// UMD (Universal Module Definition)
// see https://github.com/umdjs/umd/blob/master/returnExports.js
(function (root, factory) {
+ 'use strict';
+
+ /*global define, exports, module */
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(factory);
@@ -42,140 +45,144 @@ var ObjectPrototype = Object.prototype;
var FunctionPrototype = Function.prototype;
var StringPrototype = String.prototype;
var NumberPrototype = Number.prototype;
-var _Array_slice_ = ArrayPrototype.slice;
+var array_slice = ArrayPrototype.slice;
var array_splice = ArrayPrototype.splice;
var array_push = ArrayPrototype.push;
var array_unshift = ArrayPrototype.unshift;
+var array_concat = ArrayPrototype.concat;
var call = FunctionPrototype.call;
-// Having a toString local variable name breaks in Opera so use _toString.
-var _toString = ObjectPrototype.toString;
+// Having a toString local variable name breaks in Opera so use to_string.
+var to_string = ObjectPrototype.toString;
-var isFunction = function (val) {
- return ObjectPrototype.toString.call(val) === '[object Function]';
-};
-var isRegex = function (val) {
- return ObjectPrototype.toString.call(val) === '[object RegExp]';
-};
-var isArray = function isArray(obj) {
- return _toString.call(obj) === "[object Array]";
-};
-var isString = function isString(obj) {
- return _toString.call(obj) === "[object String]";
+var isArray = Array.isArray || function isArray(obj) {
+ return to_string.call(obj) === '[object Array]';
};
+
+var hasToStringTag = typeof Symbol === 'function' && typeof Symbol.toStringTag === 'symbol';
+var isCallable; /* inlined from https://npmjs.com/is-callable */ var fnToStr = Function.prototype.toString, tryFunctionObject = function tryFunctionObject(value) { try { fnToStr.call(value); return true; } catch (e) { return false; } }, fnClass = '[object Function]', genClass = '[object GeneratorFunction]'; isCallable = function isCallable(value) { if (typeof value !== 'function') { return false; } if (hasToStringTag) { return tryFunctionObject(value); } var strClass = to_string.call(value); return strClass === fnClass || strClass === genClass; };
+var isRegex; /* inlined from https://npmjs.com/is-regex */ var regexExec = RegExp.prototype.exec, tryRegexExec = function tryRegexExec(value) { try { regexExec.call(value); return true; } catch (e) { return false; } }, regexClass = '[object RegExp]'; isRegex = function isRegex(value) { if (typeof value !== 'object') { return false; } return hasToStringTag ? tryRegexExec(value) : to_string.call(value) === regexClass; };
+var isString; /* inlined from https://npmjs.com/is-string */ var strValue = String.prototype.valueOf, tryStringObject = function tryStringObject(value) { try { strValue.call(value); return true; } catch (e) { return false; } }, stringClass = '[object String]'; isString = function isString(value) { if (typeof value === 'string') { return true; } if (typeof value !== 'object') { return false; } return hasToStringTag ? tryStringObject(value) : to_string.call(value) === stringClass; };
+
var isArguments = function isArguments(value) {
- var str = _toString.call(value);
+ var str = to_string.call(value);
var isArgs = str === '[object Arguments]';
if (!isArgs) {
- isArgs = !isArray(str)
- && value !== null
- && typeof value === 'object'
- && typeof value.length === 'number'
- && value.length >= 0
- && isFunction(value.callee);
+ isArgs = !isArray(value) &&
+ value !== null &&
+ typeof value === 'object' &&
+ typeof value.length === 'number' &&
+ value.length >= 0 &&
+ isCallable(value.callee);
}
return isArgs;
};
-var supportsDescriptors = Object.defineProperty && (function () {
- try {
- Object.defineProperty({}, 'x', {});
- return true;
- } catch (e) { /* this is ES3 */
- return false;
- }
-}());
-
-// Define configurable, writable and non-enumerable props
-// if they don't exist.
-var defineProperty;
-if (supportsDescriptors) {
- defineProperty = function (object, name, method, forceAssign) {
- if (!forceAssign && (name in object)) { return; }
- Object.defineProperty(object, name, {
- configurable: true,
- enumerable: false,
- writable: true,
- value: method
- });
- };
-} else {
- defineProperty = function (object, name, method, forceAssign) {
- if (!forceAssign && (name in object)) { return; }
- object[name] = method;
- };
-}
-var defineProperties = function (object, map, forceAssign) {
- for (var name in map) {
- if (ObjectPrototype.hasOwnProperty.call(map, name)) {
- defineProperty(object, name, map[name], forceAssign);
- }
- }
-};
+/* inlined from http://npmjs.com/define-properties */
+var defineProperties = (function (has) {
+ var supportsDescriptors = Object.defineProperty && (function () {
+ try {
+ var obj = {};
+ Object.defineProperty(obj, 'x', { enumerable: false, value: obj });
+ for (var _ in obj) { return false; }
+ return obj.x === obj;
+ } catch (e) { /* this is ES3 */
+ return false;
+ }
+ }());
+
+ // Define configurable, writable and non-enumerable props
+ // if they don't exist.
+ var defineProperty;
+ if (supportsDescriptors) {
+ defineProperty = function (object, name, method, forceAssign) {
+ if (!forceAssign && (name in object)) { return; }
+ Object.defineProperty(object, name, {
+ configurable: true,
+ enumerable: false,
+ writable: true,
+ value: method
+ });
+ };
+ } else {
+ defineProperty = function (object, name, method, forceAssign) {
+ if (!forceAssign && (name in object)) { return; }
+ object[name] = method;
+ };
+ }
+ return function defineProperties(object, map, forceAssign) {
+ for (var name in map) {
+ if (has.call(map, name)) {
+ defineProperty(object, name, map[name], forceAssign);
+ }
+ }
+ };
+}(ObjectPrototype.hasOwnProperty));
//
// Util
// ======
//
-// ES5 9.4
-// http://es5.github.com/#x9.4
-// http://jsperf.com/to-integer
-
-function toInteger(n) {
- n = +n;
- if (n !== n) { // isNaN
- n = 0;
- } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
- n = (n > 0 || -1) * Math.floor(Math.abs(n));
- }
- return n;
-}
-
-function isPrimitive(input) {
+/* replaceable with https://npmjs.com/package/es-abstract /helpers/isPrimitive */
+var isPrimitive = function isPrimitive(input) {
var type = typeof input;
- return (
- input === null ||
- type === "undefined" ||
- type === "boolean" ||
- type === "number" ||
- type === "string"
- );
-}
+ return input === null || (type !== 'object' && type !== 'function');
+};
-function toPrimitive(input) {
- var val, valueOf, toStr;
- if (isPrimitive(input)) {
- return input;
- }
- valueOf = input.valueOf;
- if (isFunction(valueOf)) {
- val = valueOf.call(input);
- if (isPrimitive(val)) {
- return val;
+var ES = {
+ // ES5 9.4
+ // http://es5.github.com/#x9.4
+ // http://jsperf.com/to-integer
+ /* replaceable with https://npmjs.com/package/es-abstract ES5.ToInteger */
+ ToInteger: function ToInteger(num) {
+ var n = +num;
+ if (n !== n) { // isNaN
+ n = 0;
+ } else if (n !== 0 && n !== (1 / 0) && n !== -(1 / 0)) {
+ n = (n > 0 || -1) * Math.floor(Math.abs(n));
}
- }
- toStr = input.toString;
- if (isFunction(toStr)) {
- val = toStr.call(input);
- if (isPrimitive(val)) {
- return val;
+ return n;
+ },
+
+ /* replaceable with https://npmjs.com/package/es-abstract ES5.ToPrimitive */
+ ToPrimitive: function ToPrimitive(input) {
+ var val, valueOf, toStr;
+ if (isPrimitive(input)) {
+ return input;
}
- }
- throw new TypeError();
-}
+ valueOf = input.valueOf;
+ if (isCallable(valueOf)) {
+ val = valueOf.call(input);
+ if (isPrimitive(val)) {
+ return val;
+ }
+ }
+ toStr = input.toString;
+ if (isCallable(toStr)) {
+ val = toStr.call(input);
+ if (isPrimitive(val)) {
+ return val;
+ }
+ }
+ throw new TypeError();
+ },
+
+ // ES5 9.9
+ // http://es5.github.com/#x9.9
+ /* replaceable with https://npmjs.com/package/es-abstract ES5.ToObject */
+ ToObject: function (o) {
+ /*jshint eqnull: true */
+ if (o == null) { // this matches both null and undefined
+ throw new TypeError("can't convert " + o + ' to object');
+ }
+ return Object(o);
+ },
-// ES5 9.9
-// http://es5.github.com/#x9.9
-var toObject = function (o) {
- if (o == null) { // this matches both null and undefined
- throw new TypeError("can't convert " + o + " to object");
+ /* replaceable with https://npmjs.com/package/es-abstract ES5.ToUint32 */
+ ToUint32: function ToUint32(x) {
+ return x >>> 0;
}
- return Object(o);
-};
-
-var ToUint32 = function ToUint32(x) {
- return x >>> 0;
};
//
@@ -186,20 +193,20 @@ var ToUint32 = function ToUint32(x) {
// ES-5 15.3.4.5
// http://es5.github.com/#x15.3.4.5
-function Empty() {}
+var Empty = function Empty() {};
defineProperties(FunctionPrototype, {
bind: function bind(that) { // .length is 1
// 1. Let Target be the this value.
var target = this;
// 2. If IsCallable(Target) is false, throw a TypeError exception.
- if (!isFunction(target)) {
- throw new TypeError("Function.prototype.bind called on incompatible " + target);
+ if (!isCallable(target)) {
+ throw new TypeError('Function.prototype.bind called on incompatible ' + target);
}
// 3. Let A be a new (possibly empty) internal list of all of the
// argument values provided after thisArg (arg1, arg2 etc), in order.
// XXX slicedArgs will stand in for "A" if used
- var args = _Array_slice_.call(arguments, 1); // for normal call
+ var args = array_slice.call(arguments, 1); // for normal call
// 4. Let F be a new native ECMAScript object.
// 11. Set the [[Prototype]] internal property of F to the standard
// built-in Function prototype object as specified in 15.3.3.1.
@@ -209,6 +216,7 @@ defineProperties(FunctionPrototype, {
// 15.3.4.5.2.
// 14. Set the [[HasInstance]] internal property of F as described in
// 15.3.4.5.3.
+ var bound;
var binder = function () {
if (this instanceof bound) {
@@ -230,7 +238,7 @@ defineProperties(FunctionPrototype, {
var result = target.apply(
this,
- args.concat(_Array_slice_.call(arguments))
+ array_concat.call(args, array_slice.call(arguments))
);
if (Object(result) === result) {
return result;
@@ -259,7 +267,7 @@ defineProperties(FunctionPrototype, {
// equiv: target.call(this, ...boundArgs, ...args)
return target.apply(
that,
- args.concat(_Array_slice_.call(arguments))
+ array_concat.call(args, array_slice.call(arguments))
);
}
@@ -278,7 +286,7 @@ defineProperties(FunctionPrototype, {
// specified in 15.3.5.1.
var boundArgs = [];
for (var i = 0; i < boundLength; i++) {
- boundArgs.push("$" + i);
+ boundArgs.push('$' + i);
}
// XXX Build a dynamic function with desired amount of arguments is the only
@@ -287,7 +295,7 @@ defineProperties(FunctionPrototype, {
// for ex.) all use of eval or Function costructor throws an exception.
// However in all of these environments Function.prototype.bind exists
// and so this code will never be executed.
- var bound = Function("binder", "return function (" + boundArgs.join(",") + "){return binder.apply(this,arguments)}")(binder);
+ bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this, arguments); }')(binder);
if (target.prototype) {
Empty.prototype = target.prototype;
@@ -325,19 +333,6 @@ defineProperties(FunctionPrototype, {
// us it in defining shortcuts.
var owns = call.bind(ObjectPrototype.hasOwnProperty);
-// If JS engine supports accessors creating shortcuts.
-var defineGetter;
-var defineSetter;
-var lookupGetter;
-var lookupSetter;
-var supportsAccessors;
-if ((supportsAccessors = owns(ObjectPrototype, "__defineGetter__"))) {
- defineGetter = call.bind(ObjectPrototype.__defineGetter__);
- defineSetter = call.bind(ObjectPrototype.__defineSetter__);
- lookupGetter = call.bind(ObjectPrototype.__lookupGetter__);
- lookupSetter = call.bind(ObjectPrototype.__lookupSetter__);
-}
-
//
// Array
// =====
@@ -359,7 +354,7 @@ defineProperties(ArrayPrototype, {
return array_splice.apply(this, arguments);
}
}
-}, spliceNoopReturnsEmptyArray);
+}, !spliceNoopReturnsEmptyArray);
var spliceWorksWithEmptyObject = (function () {
var obj = {};
@@ -370,13 +365,13 @@ defineProperties(ArrayPrototype, {
splice: function splice(start, deleteCount) {
if (arguments.length === 0) { return []; }
var args = arguments;
- this.length = Math.max(toInteger(this.length), 0);
+ this.length = Math.max(ES.ToInteger(this.length), 0);
if (arguments.length > 0 && typeof deleteCount !== 'number') {
- args = _Array_slice_.call(arguments);
+ args = array_slice.call(arguments);
if (args.length < 2) {
args.push(this.length - start);
} else {
- args[1] = toInteger(deleteCount);
+ args[1] = ES.ToInteger(deleteCount);
}
}
return array_splice.apply(this, args);
@@ -419,8 +414,8 @@ defineProperties(Array, { isArray: isArray });
// Check failure of by-index access of string characters (IE < 9)
// and failure of `0 in boxedString` (Rhino)
-var boxedString = Object("a");
-var splitString = boxedString[0] !== "a" || !(0 in boxedString);
+var boxedString = Object('a');
+var splitString = boxedString[0] !== 'a' || !(0 in boxedString);
var properlyBoxesContext = function properlyBoxed(method) {
// Check node 0.6.21 bug where third parameter is not boxed
@@ -433,6 +428,7 @@ var properlyBoxesContext = function properlyBoxed(method) {
method.call([1], function () {
'use strict';
+
properlyBoxesStrict = typeof this === 'string';
}, 'x');
}
@@ -440,24 +436,30 @@ var properlyBoxesContext = function properlyBoxed(method) {
};
defineProperties(ArrayPrototype, {
- forEach: function forEach(fun /*, thisp*/) {
- var object = toObject(this),
- self = splitString && isString(this) ? this.split('') : object,
- thisp = arguments[1],
- i = -1,
- length = self.length >>> 0;
+ forEach: function forEach(callbackfn /*, thisArg*/) {
+ var object = ES.ToObject(this);
+ var self = splitString && isString(this) ? this.split('') : object;
+ var i = -1;
+ var length = self.length >>> 0;
+ var T;
+ if (arguments.length > 1) {
+ T = arguments[1];
+ }
// If no callback function or if callback is not a callable function
- if (!isFunction(fun)) {
- throw new TypeError(); // TODO message
+ if (!isCallable(callbackfn)) {
+ throw new TypeError('Array.prototype.forEach callback must be a function');
}
while (++i < length) {
if (i in self) {
// Invoke the callback function with call, passing arguments:
// context, property value, property key, thisArg object
- // context
- fun.call(thisp, self[i], i, object);
+ if (typeof T !== 'undefined') {
+ callbackfn.call(T, self[i], i, object);
+ } else {
+ callbackfn(self[i], i, object);
+ }
}
}
}
@@ -467,21 +469,28 @@ defineProperties(ArrayPrototype, {
// http://es5.github.com/#x15.4.4.19
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/map
defineProperties(ArrayPrototype, {
- map: function map(fun /*, thisp*/) {
- var object = toObject(this),
- self = splitString && isString(this) ? this.split('') : object,
- length = self.length >>> 0,
- result = Array(length),
- thisp = arguments[1];
+ map: function map(callbackfn/*, thisArg*/) {
+ var object = ES.ToObject(this);
+ var self = splitString && isString(this) ? this.split('') : object;
+ var length = self.length >>> 0;
+ var result = Array(length);
+ var T;
+ if (arguments.length > 1) {
+ T = arguments[1];
+ }
// If no callback function or if callback is not a callable function
- if (!isFunction(fun)) {
- throw new TypeError(fun + " is not a function");
+ if (!isCallable(callbackfn)) {
+ throw new TypeError('Array.prototype.map callback must be a function');
}
for (var i = 0; i < length; i++) {
if (i in self) {
- result[i] = fun.call(thisp, self[i], i, object);
+ if (typeof T !== 'undefined') {
+ result[i] = callbackfn.call(T, self[i], i, object);
+ } else {
+ result[i] = callbackfn(self[i], i, object);
+ }
}
}
return result;
@@ -492,23 +501,26 @@ defineProperties(ArrayPrototype, {
// http://es5.github.com/#x15.4.4.20
// https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Objects/Array/filter
defineProperties(ArrayPrototype, {
- filter: function filter(fun /*, thisp */) {
- var object = toObject(this),
- self = splitString && isString(this) ? this.split('') : object,
- length = self.length >>> 0,
- result = [],
- value,
- thisp = arguments[1];
+ filter: function filter(callbackfn /*, thisArg*/) {
+ var object = ES.ToObject(this);
+ var self = splitString && isString(this) ? this.split('') : object;
+ var length = self.length >>> 0;
+ var result = [];
+ var value;
+ var T;
+ if (arguments.length > 1) {
+ T = arguments[1];
+ }
// If no callback function or if callback is not a callable function
- if (!isFunction(fun)) {
- throw new TypeError(fun + " is not a function");
+ if (!isCallable(callbackfn)) {
+ throw new TypeError('Array.prototype.filter callback must be a function');
}
for (var i = 0; i < length; i++) {
if (i in self) {
value = self[i];
- if (fun.call(thisp, value, i, object)) {
+ if (typeof T === 'undefined' ? callbackfn(value, i, object) : callbackfn.call(T, value, i, object)) {
result.push(value);
}
}
@@ -521,19 +533,22 @@ defineProperties(ArrayPrototype, {
// http://es5.github.com/#x15.4.4.16
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/every
defineProperties(ArrayPrototype, {
- every: function every(fun /*, thisp */) {
- var object = toObject(this),
- self = splitString && isString(this) ? this.split('') : object,
- length = self.length >>> 0,
- thisp = arguments[1];
+ every: function every(callbackfn /*, thisArg*/) {
+ var object = ES.ToObject(this);
+ var self = splitString && isString(this) ? this.split('') : object;
+ var length = self.length >>> 0;
+ var T;
+ if (arguments.length > 1) {
+ T = arguments[1];
+ }
// If no callback function or if callback is not a callable function
- if (!isFunction(fun)) {
- throw new TypeError(fun + " is not a function");
+ if (!isCallable(callbackfn)) {
+ throw new TypeError('Array.prototype.every callback must be a function');
}
for (var i = 0; i < length; i++) {
- if (i in self && !fun.call(thisp, self[i], i, object)) {
+ if (i in self && !(typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) {
return false;
}
}
@@ -545,19 +560,22 @@ defineProperties(ArrayPrototype, {
// http://es5.github.com/#x15.4.4.17
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/some
defineProperties(ArrayPrototype, {
- some: function some(fun /*, thisp */) {
- var object = toObject(this),
- self = splitString && isString(this) ? this.split('') : object,
- length = self.length >>> 0,
- thisp = arguments[1];
+ some: function some(callbackfn/*, thisArg */) {
+ var object = ES.ToObject(this);
+ var self = splitString && isString(this) ? this.split('') : object;
+ var length = self.length >>> 0;
+ var T;
+ if (arguments.length > 1) {
+ T = arguments[1];
+ }
// If no callback function or if callback is not a callable function
- if (!isFunction(fun)) {
- throw new TypeError(fun + " is not a function");
+ if (!isCallable(callbackfn)) {
+ throw new TypeError('Array.prototype.some callback must be a function');
}
for (var i = 0; i < length; i++) {
- if (i in self && fun.call(thisp, self[i], i, object)) {
+ if (i in self && (typeof T === 'undefined' ? callbackfn(self[i], i, object) : callbackfn.call(T, self[i], i, object))) {
return true;
}
}
@@ -573,19 +591,19 @@ if (ArrayPrototype.reduce) {
reduceCoercesToObject = typeof ArrayPrototype.reduce.call('es5', function (_, __, ___, list) { return list; }) === 'object';
}
defineProperties(ArrayPrototype, {
- reduce: function reduce(fun /*, initial*/) {
- var object = toObject(this),
- self = splitString && isString(this) ? this.split('') : object,
- length = self.length >>> 0;
+ reduce: function reduce(callbackfn /*, initialValue*/) {
+ var object = ES.ToObject(this);
+ var self = splitString && isString(this) ? this.split('') : object;
+ var length = self.length >>> 0;
// If no callback function or if callback is not a callable function
- if (!isFunction(fun)) {
- throw new TypeError(fun + " is not a function");
+ if (!isCallable(callbackfn)) {
+ throw new TypeError('Array.prototype.reduce callback must be a function');
}
// no value to return if no initial value and an empty array
- if (!length && arguments.length === 1) {
- throw new TypeError("reduce of empty array with no initial value");
+ if (length === 0 && arguments.length === 1) {
+ throw new TypeError('reduce of empty array with no initial value');
}
var i = 0;
@@ -601,14 +619,14 @@ defineProperties(ArrayPrototype, {
// if array contains no values, no initial value to return
if (++i >= length) {
- throw new TypeError("reduce of empty array with no initial value");
+ throw new TypeError('reduce of empty array with no initial value');
}
} while (true);
}
for (; i < length; i++) {
if (i in self) {
- result = fun.call(void 0, result, self[i], i, object);
+ result = callbackfn(result, self[i], i, object);
}
}
@@ -624,22 +642,23 @@ if (ArrayPrototype.reduceRight) {
reduceRightCoercesToObject = typeof ArrayPrototype.reduceRight.call('es5', function (_, __, ___, list) { return list; }) === 'object';
}
defineProperties(ArrayPrototype, {
- reduceRight: function reduceRight(fun /*, initial*/) {
- var object = toObject(this),
- self = splitString && isString(this) ? this.split('') : object,
- length = self.length >>> 0;
+ reduceRight: function reduceRight(callbackfn/*, initial*/) {
+ var object = ES.ToObject(this);
+ var self = splitString && isString(this) ? this.split('') : object;
+ var length = self.length >>> 0;
// If no callback function or if callback is not a callable function
- if (!isFunction(fun)) {
- throw new TypeError(fun + " is not a function");
+ if (!isCallable(callbackfn)) {
+ throw new TypeError('Array.prototype.reduceRight callback must be a function');
}
// no value to return if no initial value, empty array
- if (!length && arguments.length === 1) {
- throw new TypeError("reduceRight of empty array with no initial value");
+ if (length === 0 && arguments.length === 1) {
+ throw new TypeError('reduceRight of empty array with no initial value');
}
- var result, i = length - 1;
+ var result;
+ var i = length - 1;
if (arguments.length >= 2) {
result = arguments[1];
} else {
@@ -651,7 +670,7 @@ defineProperties(ArrayPrototype, {
// if array contains no values, no initial value to return
if (--i < 0) {
- throw new TypeError("reduceRight of empty array with no initial value");
+ throw new TypeError('reduceRight of empty array with no initial value');
}
} while (true);
}
@@ -662,7 +681,7 @@ defineProperties(ArrayPrototype, {
do {
if (i in self) {
- result = fun.call(void 0, result, self[i], i, object);
+ result = callbackfn(result, self[i], i, object);
}
} while (i--);
@@ -675,23 +694,23 @@ defineProperties(ArrayPrototype, {
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/indexOf
var hasFirefox2IndexOfBug = Array.prototype.indexOf && [0, 1].indexOf(1, 2) !== -1;
defineProperties(ArrayPrototype, {
- indexOf: function indexOf(sought /*, fromIndex */ ) {
- var self = splitString && isString(this) ? this.split('') : toObject(this),
- length = self.length >>> 0;
+ indexOf: function indexOf(searchElement /*, fromIndex */) {
+ var self = splitString && isString(this) ? this.split('') : ES.ToObject(this);
+ var length = self.length >>> 0;
- if (!length) {
+ if (length === 0) {
return -1;
}
var i = 0;
if (arguments.length > 1) {
- i = toInteger(arguments[1]);
+ i = ES.ToInteger(arguments[1]);
}
// handle negative indices
i = i >= 0 ? i : Math.max(0, length + i);
for (; i < length; i++) {
- if (i in self && self[i] === sought) {
+ if (i in self && self[i] === searchElement) {
return i;
}
}
@@ -704,21 +723,21 @@ defineProperties(ArrayPrototype, {
// https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/lastIndexOf
var hasFirefox2LastIndexOfBug = Array.prototype.lastIndexOf && [0, 1].lastIndexOf(0, -3) !== -1;
defineProperties(ArrayPrototype, {
- lastIndexOf: function lastIndexOf(sought /*, fromIndex */) {
- var self = splitString && isString(this) ? this.split('') : toObject(this),
- length = self.length >>> 0;
+ lastIndexOf: function lastIndexOf(searchElement /*, fromIndex */) {
+ var self = splitString && isString(this) ? this.split('') : ES.ToObject(this);
+ var length = self.length >>> 0;
- if (!length) {
+ if (length === 0) {
return -1;
}
var i = length - 1;
if (arguments.length > 1) {
- i = Math.min(i, toInteger(arguments[1]));
+ i = Math.min(i, ES.ToInteger(arguments[1]));
}
// handle negative indices
i = i >= 0 ? i : length - Math.abs(i);
for (; i >= 0; i--) {
- if (i in self && sought === self[i]) {
+ if (i in self && searchElement === self[i]) {
return i;
}
}
@@ -735,37 +754,40 @@ defineProperties(ArrayPrototype, {
// http://es5.github.com/#x15.2.3.14
// http://whattheheadsaid.com/2010/10/a-safer-object-keys-compatibility-implementation
-var hasDontEnumBug = !({'toString': null}).propertyIsEnumerable('toString'),
- hasProtoEnumBug = (function () {}).propertyIsEnumerable('prototype'),
+var hasDontEnumBug = !({ 'toString': null }).propertyIsEnumerable('toString'),
+ hasProtoEnumBug = function () {}.propertyIsEnumerable('prototype'),
+ hasStringEnumBug = !owns('x', '0'),
dontEnums = [
- "toString",
- "toLocaleString",
- "valueOf",
- "hasOwnProperty",
- "isPrototypeOf",
- "propertyIsEnumerable",
- "constructor"
+ 'toString',
+ 'toLocaleString',
+ 'valueOf',
+ 'hasOwnProperty',
+ 'isPrototypeOf',
+ 'propertyIsEnumerable',
+ 'constructor'
],
dontEnumsLength = dontEnums.length;
defineProperties(Object, {
keys: function keys(object) {
- var isFn = isFunction(object),
+ var isFn = isCallable(object),
isArgs = isArguments(object),
isObject = object !== null && typeof object === 'object',
isStr = isObject && isString(object);
if (!isObject && !isFn && !isArgs) {
- throw new TypeError("Object.keys called on a non-object");
+ throw new TypeError('Object.keys called on a non-object');
}
var theKeys = [];
var skipProto = hasProtoEnumBug && isFn;
- if (isStr || isArgs) {
+ if ((isStr && hasStringEnumBug) || isArgs) {
for (var i = 0; i < object.length; ++i) {
theKeys.push(String(i));
}
- } else {
+ }
+
+ if (!isArgs) {
for (var name in object) {
if (!(skipProto && name === 'prototype') && owns(object, name)) {
theKeys.push(String(name));
@@ -815,14 +837,14 @@ defineProperties(Object, {
// The time zone is always UTC, denoted by the suffix Z. If the time value of
// this object is not a finite Number a RangeError exception is thrown.
var negativeDate = -62198755200000;
-var negativeYearString = "-000001";
+var negativeYearString = '-000001';
var hasNegativeDateBug = Date.prototype.toISOString && new Date(negativeDate).toISOString().indexOf(negativeYearString) === -1;
defineProperties(Date.prototype, {
toISOString: function toISOString() {
var result, length, value, year, month;
if (!isFinite(this)) {
- throw new RangeError("Date.prototype.toISOString called on non-finite value.");
+ throw new RangeError('Date.prototype.toISOString called on non-finite value.');
}
year = this.getUTCFullYear();
@@ -835,8 +857,8 @@ defineProperties(Date.prototype, {
// the date time string format is specified in 15.9.1.15.
result = [month + 1, this.getUTCDate(), this.getUTCHours(), this.getUTCMinutes(), this.getUTCSeconds()];
year = (
- (year < 0 ? "-" : (year > 9999 ? "+" : "")) +
- ("00000" + Math.abs(year)).slice(0 <= year && year <= 9999 ? -4 : -6)
+ (year < 0 ? '-' : (year > 9999 ? '+' : '')) +
+ ('00000' + Math.abs(year)).slice((0 <= year && year <= 9999) ? -4 : -6)
);
length = result.length;
@@ -845,37 +867,34 @@ defineProperties(Date.prototype, {
// pad months, days, hours, minutes, and seconds to have two
// digits.
if (value < 10) {
- result[length] = "0" + value;
+ result[length] = '0' + value;
}
}
// pad milliseconds to have three digits.
return (
- year + "-" + result.slice(0, 2).join("-") +
- "T" + result.slice(2).join(":") + "." +
- ("000" + this.getUTCMilliseconds()).slice(-3) + "Z"
+ year + '-' + result.slice(0, 2).join('-') +
+ 'T' + result.slice(2).join(':') + '.' +
+ ('000' + this.getUTCMilliseconds()).slice(-3) + 'Z'
);
}
}, hasNegativeDateBug);
-
// ES5 15.9.5.44
// http://es5.github.com/#x15.9.5.44
// This function provides a String representation of a Date object for use by
// JSON.stringify (15.12.3).
-var dateToJSONIsSupported = false;
-try {
- dateToJSONIsSupported = (
- Date.prototype.toJSON &&
- new Date(NaN).toJSON() === null &&
- new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 &&
- Date.prototype.toJSON.call({ // generic
- toISOString: function () {
- return true;
- }
- })
- );
-} catch (e) {
-}
+var dateToJSONIsSupported = (function () {
+ try {
+ return Date.prototype.toJSON &&
+ new Date(NaN).toJSON() === null &&
+ new Date(negativeDate).toJSON().indexOf(negativeYearString) !== -1 &&
+ Date.prototype.toJSON.call({ // generic
+ toISOString: function () { return true; }
+ });
+ } catch (e) {
+ return false;
+ }
+}());
if (!dateToJSONIsSupported) {
Date.prototype.toJSON = function toJSON(key) {
// When the toJSON method is called with argument key, the following
@@ -883,24 +902,23 @@ if (!dateToJSONIsSupported) {
// 1. Let O be the result of calling ToObject, giving it the this
// value as its argument.
- // 2. Let tv be toPrimitive(O, hint Number).
- var o = Object(this),
- tv = toPrimitive(o),
- toISO;
+ // 2. Let tv be ES.ToPrimitive(O, hint Number).
+ var O = Object(this);
+ var tv = ES.ToPrimitive(O);
// 3. If tv is a Number and is not finite, return null.
- if (typeof tv === "number" && !isFinite(tv)) {
+ if (typeof tv === 'number' && !isFinite(tv)) {
return null;
}
// 4. Let toISO be the result of calling the [[Get]] internal method of
// O with argument "toISOString".
- toISO = o.toISOString;
+ var toISO = O.toISOString;
// 5. If IsCallable(toISO) is false, throw a TypeError exception.
- if (typeof toISO !== "function") {
- throw new TypeError("toISOString property is not callable");
+ if (!isCallable(toISO)) {
+ throw new TypeError('toISOString property is not callable');
}
// 6. Return the result of calling the [[Call]] internal method of
// toISO with O as the this value and an empty argument list.
- return toISO.call(o);
+ return toISO.call(O);
// NOTE 1 The argument is ignored.
@@ -918,20 +936,23 @@ if (!dateToJSONIsSupported) {
// based on work shared by Daniel Friesen (dantman)
// http://gist.github.com/303249
var supportsExtendedYears = Date.parse('+033658-09-27T01:46:40.000Z') === 1e15;
-var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z'));
-var doesNotParseY2KNewYear = isNaN(Date.parse("2000-01-01T00:00:00.000Z"));
+var acceptsInvalidDates = !isNaN(Date.parse('2012-04-04T24:00:00.500Z')) || !isNaN(Date.parse('2012-11-31T23:59:59.000Z')) || !isNaN(Date.parse('2012-12-31T23:59:60.000Z'));
+var doesNotParseY2KNewYear = isNaN(Date.parse('2000-01-01T00:00:00.000Z'));
if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExtendedYears) {
// XXX global assignment won't work in embeddings that use
// an alternate object for the context.
+ /*global Date: true */
+ /*eslint-disable no-undef*/
Date = (function (NativeDate) {
-
+ /*eslint-enable no-undef*/
// Date.length === 7
- function Date(Y, M, D, h, m, s, ms) {
+ var DateShim = function Date(Y, M, D, h, m, s, ms) {
var length = arguments.length;
+ var date;
if (this instanceof NativeDate) {
- var date = length === 1 && String(Y) === Y ? // isString(Y)
+ date = length === 1 && String(Y) === Y ? // isString(Y)
// We explicitly pass it through parse:
- new NativeDate(Date.parse(Y)) :
+ new NativeDate(DateShim.parse(Y)) :
// We have to manually make calls depending on argument
// length here
length >= 7 ? new NativeDate(Y, M, D, h, m, s, ms) :
@@ -942,41 +963,40 @@ if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExt
length >= 2 ? new NativeDate(Y, M) :
length >= 1 ? new NativeDate(Y) :
new NativeDate();
- // Prevent mixups with unfixed Date object
- date.constructor = Date;
- return date;
+ } else {
+ date = NativeDate.apply(this, arguments);
}
- return NativeDate.apply(this, arguments);
- }
+ // Prevent mixups with unfixed Date object
+ defineProperties(date, { constructor: DateShim }, true);
+ return date;
+ };
// 15.9.1.15 Date Time String Format.
- var isoDateExpression = new RegExp("^" +
- "(\\d{4}|[\+\-]\\d{6})" + // four-digit year capture or sign +
+ var isoDateExpression = new RegExp('^' +
+ '(\\d{4}|[+-]\\d{6})' + // four-digit year capture or sign +
// 6-digit extended year
- "(?:-(\\d{2})" + // optional month capture
- "(?:-(\\d{2})" + // optional day capture
- "(?:" + // capture hours:minutes:seconds.milliseconds
- "T(\\d{2})" + // hours capture
- ":(\\d{2})" + // minutes capture
- "(?:" + // optional :seconds.milliseconds
- ":(\\d{2})" + // seconds capture
- "(?:(\\.\\d{1,}))?" + // milliseconds capture
- ")?" +
- "(" + // capture UTC offset component
- "Z|" + // UTC capture
- "(?:" + // offset specifier +/-hours:minutes
- "([-+])" + // sign capture
- "(\\d{2})" + // hours offset capture
- ":(\\d{2})" + // minutes offset capture
- ")" +
- ")?)?)?)?" +
- "$");
-
- var months = [
- 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
- ];
-
- function dayFromMonth(year, month) {
+ '(?:-(\\d{2})' + // optional month capture
+ '(?:-(\\d{2})' + // optional day capture
+ '(?:' + // capture hours:minutes:seconds.milliseconds
+ 'T(\\d{2})' + // hours capture
+ ':(\\d{2})' + // minutes capture
+ '(?:' + // optional :seconds.milliseconds
+ ':(\\d{2})' + // seconds capture
+ '(?:(\\.\\d{1,}))?' + // milliseconds capture
+ ')?' +
+ '(' + // capture UTC offset component
+ 'Z|' + // UTC capture
+ '(?:' + // offset specifier +/-hours:minutes
+ '([-+])' + // sign capture
+ '(\\d{2})' + // hours offset capture
+ ':(\\d{2})' + // minutes offset capture
+ ')' +
+ ')?)?)?)?' +
+ '$');
+
+ var months = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];
+
+ var dayFromMonth = function dayFromMonth(year, month) {
var t = month > 1 ? 1 : 0;
return (
months[month] +
@@ -985,25 +1005,31 @@ if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExt
Math.floor((year - 1601 + t) / 400) +
365 * (year - 1970)
);
- }
+ };
- function toUTC(t) {
+ var toUTC = function toUTC(t) {
return Number(new NativeDate(1970, 0, 1, 0, 0, 0, t));
- }
+ };
// Copy any custom methods a 3rd party library may have added
for (var key in NativeDate) {
- Date[key] = NativeDate[key];
+ if (owns(NativeDate, key)) {
+ DateShim[key] = NativeDate[key];
+ }
}
// Copy "native" methods explicitly; they may be non-enumerable
- Date.now = NativeDate.now;
- Date.UTC = NativeDate.UTC;
- Date.prototype = NativeDate.prototype;
- Date.prototype.constructor = Date;
+ defineProperties(DateShim, {
+ now: NativeDate.now,
+ UTC: NativeDate.UTC
+ }, true);
+ DateShim.prototype = NativeDate.prototype;
+ defineProperties(DateShim.prototype, {
+ constructor: DateShim
+ }, true);
// Upgrade Date.parse to handle simplified ISO 8601 strings
- Date.parse = function parse(string) {
+ DateShim.parse = function parse(string) {
var match = isoDateExpression.exec(string);
if (match) {
// parse months, days, hours, minutes, seconds, and milliseconds
@@ -1020,7 +1046,7 @@ if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExt
// (ES 5.1 bug)
// see https://bugs.ecmascript.org/show_bug.cgi?id=112
isLocalTime = Boolean(match[4] && !match[8]),
- signOffset = match[9] === "-" ? 1 : -1,
+ signOffset = match[9] === '-' ? 1 : -1,
hourOffset = Number(match[10] || 0),
minuteOffset = Number(match[11] || 0),
result;
@@ -1059,8 +1085,9 @@ if (!Date.parse || doesNotParseY2KNewYear || acceptsInvalidDates || !supportsExt
return NativeDate.parse.apply(this, arguments);
};
- return Date;
- })(Date);
+ return DateShim;
+ }(Date));
+ /*global Date: false */
}
// ES5 15.9.4.4
@@ -1071,7 +1098,6 @@ if (!Date.now) {
};
}
-
//
// Number
// ======
@@ -1080,10 +1106,10 @@ if (!Date.now) {
// ES5.1 15.7.4.5
// http://es5.github.com/#x15.7.4.5
var hasToFixedBugs = NumberPrototype.toFixed && (
- (0.00008).toFixed(3) !== '0.000'
- || (0.9).toFixed(0) !== '1'
- || (1.255).toFixed(2) !== '1.25'
- || (1000000000000000128).toFixed(0) !== "1000000000000000128"
+ (0.00008).toFixed(3) !== '0.000' ||
+ (0.9).toFixed(0) !== '1' ||
+ (1.255).toFixed(2) !== '1.25' ||
+ (1000000000000000128).toFixed(0) !== '1000000000000000128'
);
var toFixedHelpers = {
@@ -1092,10 +1118,11 @@ var toFixedHelpers = {
data: [0, 0, 0, 0, 0, 0],
multiply: function multiply(n, c) {
var i = -1;
+ var c2 = c;
while (++i < toFixedHelpers.size) {
- c += n * toFixedHelpers.data[i];
- toFixedHelpers.data[i] = c % toFixedHelpers.base;
- c = Math.floor(c / toFixedHelpers.base);
+ c2 += n * toFixedHelpers.data[i];
+ toFixedHelpers.data[i] = c2 % toFixedHelpers.base;
+ c2 = Math.floor(c2 / toFixedHelpers.base);
}
},
divide: function divide(n) {
@@ -1126,13 +1153,14 @@ var toFixedHelpers = {
},
log: function log(x) {
var n = 0;
- while (x >= 4096) {
+ var x2 = x;
+ while (x2 >= 4096) {
n += 12;
- x /= 4096;
+ x2 /= 4096;
}
- while (x >= 2) {
+ while (x2 >= 2) {
n += 1;
- x /= 2;
+ x2 /= 2;
}
return n;
}
@@ -1147,14 +1175,14 @@ defineProperties(NumberPrototype, {
f = f !== f ? 0 : Math.floor(f);
if (f < 0 || f > 20) {
- throw new RangeError("Number.toFixed called with invalid number of decimals");
+ throw new RangeError('Number.toFixed called with invalid number of decimals');
}
x = Number(this);
// Test for NaN
if (x !== x) {
- return "NaN";
+ return 'NaN';
}
// If it is too big or small, return the string value of the number
@@ -1162,14 +1190,14 @@ defineProperties(NumberPrototype, {
return String(x);
}
- s = "";
+ s = '';
if (x < 0) {
- s = "-";
+ s = '-';
x = -x;
}
- m = "0";
+ m = '0';
if (x > 1e-21) {
// 1e-21 < x < 1e21
@@ -1225,7 +1253,6 @@ defineProperties(NumberPrototype, {
}
}, hasToFixedBugs);
-
//
// String
// ======
@@ -1250,38 +1277,38 @@ var string_split = StringPrototype.split;
if (
'ab'.split(/(?:ab)*/).length !== 2 ||
'.'.split(/(.?)(.?)/).length !== 4 ||
- 'tesst'.split(/(s)*/)[1] === "t" ||
+ 'tesst'.split(/(s)*/)[1] === 't' ||
'test'.split(/(?:)/, -1).length !== 4 ||
''.split(/.?/).length ||
'.'.split(/()()/).length > 1
) {
(function () {
- var compliantExecNpcg = /()??/.exec("")[1] === void 0; // NPCG: nonparticipating capturing group
+ var compliantExecNpcg = typeof (/()??/).exec('')[1] === 'undefined'; // NPCG: nonparticipating capturing group
StringPrototype.split = function (separator, limit) {
var string = this;
- if (separator === void 0 && limit === 0) {
+ if (typeof separator === 'undefined' && limit === 0) {
return [];
}
// If `separator` is not a regex, use native split
- if (_toString.call(separator) !== "[object RegExp]") {
+ if (!isRegex(separator)) {
return string_split.call(this, separator, limit);
}
- var output = [],
- flags = (separator.ignoreCase ? "i" : "") +
- (separator.multiline ? "m" : "") +
- (separator.extended ? "x" : "") + // Proposed for ES6
- (separator.sticky ? "y" : ""), // Firefox 3+
+ var output = [];
+ var flags = (separator.ignoreCase ? 'i' : '') +
+ (separator.multiline ? 'm' : '') +
+ (separator.extended ? 'x' : '') + // Proposed for ES6
+ (separator.sticky ? 'y' : ''), // Firefox 3+
lastLastIndex = 0,
// Make `global` and avoid `lastIndex` issues by working with a copy
separator2, match, lastIndex, lastLength;
- separator = new RegExp(separator.source, flags + "g");
- string += ""; // Type-convert
+ var separatorCopy = new RegExp(separator.source, flags + 'g');
+ string += ''; // Type-convert
if (!compliantExecNpcg) {
// Doesn't need flags gy, but they don't hurt
- separator2 = new RegExp("^" + separator.source + "$(?!\\s)", flags);
+ separator2 = new RegExp('^' + separatorCopy.source + '$(?!\\s)', flags);
}
/* Values for `limit`, per the spec:
* If undefined: 4294967295 // Math.pow(2, 32) - 1
@@ -1290,46 +1317,50 @@ if (
* If negative number: 4294967296 - Math.floor(Math.abs(limit))
* If other: Type-convert, then use the above rules
*/
- limit = limit === void 0 ?
+ var splitLimit = typeof limit === 'undefined' ?
-1 >>> 0 : // Math.pow(2, 32) - 1
- ToUint32(limit);
- while (match = separator.exec(string)) {
- // `separator.lastIndex` is not reliable cross-browser
+ ES.ToUint32(limit);
+ match = separatorCopy.exec(string);
+ while (match) {
+ // `separatorCopy.lastIndex` is not reliable cross-browser
lastIndex = match.index + match[0].length;
if (lastIndex > lastLastIndex) {
output.push(string.slice(lastLastIndex, match.index));
// Fix browsers whose `exec` methods don't consistently return `undefined` for
// nonparticipating capturing groups
if (!compliantExecNpcg && match.length > 1) {
+ /*eslint-disable no-loop-func */
match[0].replace(separator2, function () {
for (var i = 1; i < arguments.length - 2; i++) {
- if (arguments[i] === void 0) {
+ if (typeof arguments[i] === 'undefined') {
match[i] = void 0;
}
}
});
+ /*eslint-enable no-loop-func */
}
if (match.length > 1 && match.index < string.length) {
- ArrayPrototype.push.apply(output, match.slice(1));
+ array_push.apply(output, match.slice(1));
}
lastLength = match[0].length;
lastLastIndex = lastIndex;
- if (output.length >= limit) {
+ if (output.length >= splitLimit) {
break;
}
}
- if (separator.lastIndex === match.index) {
- separator.lastIndex++; // Avoid an infinite loop
+ if (separatorCopy.lastIndex === match.index) {
+ separatorCopy.lastIndex++; // Avoid an infinite loop
}
+ match = separatorCopy.exec(string);
}
if (lastLastIndex === string.length) {
- if (lastLength || !separator.test("")) {
- output.push("");
+ if (lastLength || !separatorCopy.test('')) {
+ output.push('');
}
} else {
output.push(string.slice(lastLastIndex));
}
- return output.length > limit ? output.slice(0, limit) : output;
+ return output.length > splitLimit ? output.slice(0, splitLimit) : output;
};
}());
@@ -1339,9 +1370,9 @@ if (
// then the output array is truncated so that it contains no more than limit
// elements.
// "0".split(undefined, 0) -> []
-} else if ("0".split(void 0, 0).length) {
+} else if ('0'.split(void 0, 0).length) {
StringPrototype.split = function split(separator, limit) {
- if (separator === void 0 && limit === 0) { return []; }
+ if (typeof separator === 'undefined' && limit === 0) { return []; }
return string_split.call(this, separator, limit);
};
}
@@ -1357,7 +1388,7 @@ var replaceReportsGroupsCorrectly = (function () {
if (!replaceReportsGroupsCorrectly) {
StringPrototype.replace = function replace(searchValue, replaceValue) {
- var isFn = isFunction(replaceValue);
+ var isFn = isCallable(replaceValue);
var hasCapturingGroups = isRegex(searchValue) && (/\)[*?]/).test(searchValue.source);
if (!isFn || !hasCapturingGroups) {
return str_replace.call(this, searchValue, replaceValue);
@@ -1366,7 +1397,7 @@ if (!replaceReportsGroupsCorrectly) {
var length = arguments.length;
var originalLastIndex = searchValue.lastIndex;
searchValue.lastIndex = 0;
- var args = searchValue.exec(match);
+ var args = searchValue.exec(match) || [];
searchValue.lastIndex = originalLastIndex;
args.push(arguments[length - 2], arguments[length - 1]);
return replaceValue.apply(this, args);
@@ -1382,48 +1413,47 @@ if (!replaceReportsGroupsCorrectly) {
// normalized across all browsers
// [bugfix, IE lt 9] IE < 9 substr() with negative value not working in IE
var string_substr = StringPrototype.substr;
-var hasNegativeSubstrBug = "".substr && "0b".substr(-1) !== "b";
+var hasNegativeSubstrBug = ''.substr && '0b'.substr(-1) !== 'b';
defineProperties(StringPrototype, {
substr: function substr(start, length) {
- return string_substr.call(
- this,
- start < 0 ? ((start = this.length + start) < 0 ? 0 : start) : start,
- length
- );
+ var normalizedStart = start;
+ if (start < 0) {
+ normalizedStart = Math.max(this.length + start, 0);
+ }
+ return string_substr.call(this, normalizedStart, length);
}
}, hasNegativeSubstrBug);
// ES5 15.5.4.20
// whitespace from: http://es5.github.io/#x15.5.4.20
-var ws = "\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003" +
- "\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028" +
- "\u2029\uFEFF";
+var ws = '\x09\x0A\x0B\x0C\x0D\x20\xA0\u1680\u180E\u2000\u2001\u2002\u2003' +
+ '\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028' +
+ '\u2029\uFEFF';
var zeroWidth = '\u200b';
-var wsRegexChars = "[" + ws + "]";
-var trimBeginRegexp = new RegExp("^" + wsRegexChars + wsRegexChars + "*");
-var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + "*$");
+var wsRegexChars = '[' + ws + ']';
+var trimBeginRegexp = new RegExp('^' + wsRegexChars + wsRegexChars + '*');
+var trimEndRegexp = new RegExp(wsRegexChars + wsRegexChars + '*$');
var hasTrimWhitespaceBug = StringPrototype.trim && (ws.trim() || !zeroWidth.trim());
defineProperties(StringPrototype, {
// http://blog.stevenlevithan.com/archives/faster-trim-javascript
// http://perfectionkills.com/whitespace-deviations/
trim: function trim() {
- if (this === void 0 || this === null) {
- throw new TypeError("can't convert " + this + " to object");
+ if (typeof this === 'undefined' || this === null) {
+ throw new TypeError("can't convert " + this + ' to object');
}
- return String(this).replace(trimBeginRegexp, "").replace(trimEndRegexp, "");
+ return String(this).replace(trimBeginRegexp, '').replace(trimEndRegexp, '');
}
}, hasTrimWhitespaceBug);
// ES-5 15.1.2.2
if (parseInt(ws + '08') !== 8 || parseInt(ws + '0x16') !== 22) {
+ /*global parseInt: true */
parseInt = (function (origParseInt) {
var hexRegex = /^0[xX]/;
- return function parseIntES5(str, radix) {
- str = String(str).trim();
- if (!Number(radix)) {
- radix = hexRegex.test(str) ? 16 : 10;
- }
- return origParseInt(str, radix);
+ return function parseInt(str, radix) {
+ var string = String(str).trim();
+ var defaultedRadix = Number(radix) || (hexRegex.test(string) ? 16 : 10);
+ return origParseInt(string, defaultedRadix);
};
}(parseInt));
}
diff --git a/resources/lib/jquery.client/jquery.client.js b/resources/lib/jquery.client/jquery.client.js
index 1560c7d2..8257d85b 100644
--- a/resources/lib/jquery.client/jquery.client.js
+++ b/resources/lib/jquery.client/jquery.client.js
@@ -1,5 +1,5 @@
/*!
- * jQuery Client v1.0.0
+ * jQuery Client v2.0.0
* https://www.mediawiki.org/wiki/JQuery_Client
*
* Copyright 2010-2015 jquery-client maintainers and other contributors.
@@ -182,9 +182,12 @@
version = match[1];
}
}
- // And IE 12's different lies about not being IE
+ // And MS Edge's lies about being Chrome
+ //
+ // It's different enough from classic IE Trident engine that they do this
+ // to avoid getting caught by MSIE-specific browser sniffing.
if ( name === 'chrome' && ( match = ua.match( /\bedge\/([0-9\.]*)/ ) ) ) {
- name = 'msie';
+ name = 'edge';
version = match[1];
layout = 'edge';
layoutversion = parseInt( match[1], 10 );
diff --git a/resources/lib/jquery.i18n/CREDITS b/resources/lib/jquery.i18n/CREDITS
new file mode 100644
index 00000000..3a4eb5e2
--- /dev/null
+++ b/resources/lib/jquery.i18n/CREDITS
@@ -0,0 +1,9 @@
+Credits
+=======
+
+Santhosh Thottingal
+Amir E. Aharoni
+Siebrand Mazeland
+Niklas Laxström
+Neil Kandalgaonkar
+David Chan
diff --git a/resources/lib/jquery.i18n/GPL-LICENSE b/resources/lib/jquery.i18n/GPL-LICENSE
new file mode 100644
index 00000000..d159169d
--- /dev/null
+++ b/resources/lib/jquery.i18n/GPL-LICENSE
@@ -0,0 +1,339 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
diff --git a/resources/lib/jquery.i18n/MIT-LICENSE b/resources/lib/jquery.i18n/MIT-LICENSE
new file mode 100644
index 00000000..f3a03b7e
--- /dev/null
+++ b/resources/lib/jquery.i18n/MIT-LICENSE
@@ -0,0 +1,21 @@
+Copyright (c) 2012-2013 Santhosh Thottingal and other
+contributors. See CREDITS for a list.
+
+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.i18n/README.md b/resources/lib/jquery.i18n/README.md
new file mode 100644
index 00000000..da82c2bc
--- /dev/null
+++ b/resources/lib/jquery.i18n/README.md
@@ -0,0 +1,432 @@
+jQuery.i18n
+===========
+
+jQuery.i18n is a jQuery based Javascript internationalization library. It helps you to internationalize your web applications easily.
+
+This is a project by Wikimedia foundation's [Language Engineering team](http://wikimediafoundation.org/wiki/Language_Engineering_team) and used in some of the Wikimedia Foundation projects like Universal Language Selector.
+
+The jquery.i18n library uses a json based localization file format, "banana", which is used as the localization file format for MediaWiki and other projects.
+
+Features
+========
+* Simple file format - JSON. Easily readable for humans and machines.
+* Author and metadata information is not lost anywhere. There are other file formats using comments to store this.
+* Uses MediaWiki convention for placeholders. Easily readable and proven convention. Example: ```There are $1 cars```
+* Supports plural conversion without using extra messages for all plural forms. Plural rule handling is done using CLDR. Covers a wide range of languages
+* Supports gender. By passing the gender value, you get correct sentences according to gender.
+* Supports grammar forms. jquery.i18n has a basic but extensible grammar conversion support
+* Fallback chains for all languages.
+* Data api- the message key. Example: ```<li data-i18n="message-key"></li>```.
+* Dynamic change of interface language without refreshing a webpage.
+* Nestable grammar, plural, gender support. These constructs can be nested to any arbitrary level for supporting sophisticated message localization
+* Message documentation through special language code ```qqq```
+* Extensible message parser to add or customize magic words in the messages. Example: ```{sitename}``` or ```[[link]]``
+
+
+Quick start
+-----------
+
+```bash
+git clone https://github.com/wikimedia/jquery.i18n.git
+cd jquery.i18n
+git submodule update --init
+```
+
+Testing
+-------
+
+```shell
+npm install
+```
+
+To run tests locally, run `npm test`, and this will run the tests.
+
+Message File Format
+===================
+
+The message files are json formatted. As a convention you can have a folder named i18n inside your source code. For each language or locale, have a file named like languagecode.json.
+
+Example:
+```
+App
+ |--src
+ |--doc
+ |--i18n
+ |--ar.json
+ |--de.json
+ |--en.json
+ |--he.json
+ |--hi.json
+ |--fr.json
+ |--qqq.json
+```
+
+A simple en.json file example is given below
+
+```json
+{
+ "@metadata": {
+ "authors": [
+ "Alice",
+ "David",
+ "Santhosh"
+ ],
+ "last-updated": "2012-09-21",
+ "locale": "en",
+ "message-documentation": "qqq",
+ "AnotherMetadata": "AnotherMedatadataValue"
+ },
+ "appname-title": "Example Application",
+ "appname-sub-title": "An example application with jquery.i18n",
+ "appname-header-introduction": "Introduction",
+ "appname-about": "About this application",
+ "appname-footer": "Footer text"
+}
+```
+
+The json file should be a valid json. The ```@metadata``` holds all kind of data that are not messages. You can store author information, copyright, updated date or anything there.
+
+Messages are key value pairs. It is a good convention to prefix your appname to message keys to make the messages unique. It acts as the namespace for the message keys. It is also a good convention to have the message keys with ```-``` separated words, all in lower case.
+
+If you are curious to see some real jquery.i18n message file from other projects:
+
+- message files of MediaWiki https://github.com/wikimedia/mediawiki-core/tree/master/languages/i18n
+- message files from jquery.uls project https://github.com/wikimedia/jquery.uls/blob/master/i18n
+
+Single message file for all languages
+-------------------------------------
+There are some alternate message file format supported for different use cases. If your application is not big, and want all the translation in a single file, you can have it as shown in the below example:
+
+```json
+{
+ "@metadata": {
+ "authors": [
+ "Alice",
+ "David",
+ "Santhosh"
+ ],
+ "last-updated": "2012-09-21",
+ "locale": "en",
+ "message-documentation": "qqq",
+ "AnotherMetadata": "AnotherMedatadataValue"
+ },
+ "en": {
+ "appname-title": "Example Application",
+ "appname-sub-title": "An example application with jquery.i18n",
+ "appname-header-introduction": "Introduction",
+ "appname-about": "About this application",
+ "appname-footer": "Footer text"
+ },
+ "ml": {
+ "appname-title": "അപ്ലിക്കേഷന്‍ ഉദാഹരണം",
+ "appname-sub-title": "jquery.i18n ഉപയോഗിച്ചുള്ള അപ്ലിക്കേഷന്‍ ഉദാഹരണം",
+ "appname-header-introduction": "ആമുഖം",
+ "appname-about": "ഈ അപ്ലിക്കേഷനെപ്പറ്റി",
+ "appname-footer": "അടിക്കുറിപ്പു്"
+ }
+}
+```
+
+Here the json file contains language code as key value and messagekey-message pairs as the value for all language pairs. You can choose this format or per-language file formats depending on your use case. Per-language files are more convenient for collaboration, version controlling, scalability, etc.
+
+In this approach, it is also possible to give a file name as the value of language code.
+
+```json
+{
+ "@metadata": {
+ "authors": [
+ "Alice",
+ "David",
+ "Santhosh"
+ ],
+ "last-updated": "2012-09-21",
+ "locale": "en",
+ "message-documentation": "qqq",
+ "AnotherMetadata": "AnotherMedatadataValue"
+ },
+ "en": {
+ "appname-title": "Example Application",
+ "appname-sub-title": "An example application with jquery.i18n",
+ "appname-header-introduction": "Introduction",
+ "appname-about": "About this application",
+ "appname-footer": "Footer text"
+ },
+ "ml": "path/to/ml.json"
+}
+```
+
+Translation
+===========
+To translate the jquery.i18n application, depending on the expertise of the translator, there are multiple ways.
+
+* Editing the json files directly - Suitable for translators with technical background. Also suitable if your application is small and you want to work with only a small number of languages
+* Providing a translation interface along with your application: Suitable for proprietary or private applications with significant amount of translators
+* Using open source translation platforms like translatewiki.net. The MediaWiki and jquery.uls from previous examples use translatewiki.net for crowdsourced message translation. Translatewiki.net can update your code repo in regular intervals with updated translations. Highly recommended if your application is opensource and want localized to as many as languages possible with maximum number of translators.
+
+Usage
+=====
+
+## Switching locale
+
+While initializing the `jquery.i18n`, the locale for the page can be given using the `locale` option. For example
+
+```javascript
+$.i18n( {
+ locale: 'he' // Locale is Hebrew
+} );
+```
+
+In case locale option is not given, `jquery.i18n` plugin will use the language attribute given for the html tag. For example
+
+```html
+<html lang="he" dir="rtl">
+```
+
+In this case the locale will be he(Hebrew). If that `lang` attribute is also missing, it will try to use the locale specified by the browser.
+
+It is possible to switch to another locale after plugin is initialized. See below example:
+
+```javascript
+$.i18n({
+ locale: 'he' // Locale is Hebrew
+});
+$.i18n( 'message_hello' ); // This will give the Hebrew translation of message key `message_hello`.
+$.i18n().locale = 'ml'; // Now onwards locale is 'Malayalam'
+$.i18n( 'message_hello' ); // This will give the Malayalam translation of message key `message_hello`.
+```
+
+## Message Loading
+
+JSON formatted messages can be loaded to the plugin using multiple ways.
+
+### Dynamic loading using `load` method.
+
+Following example shows loading messages for two locales- localex, and localey. Here localex and localey are just examples. They should be valid IS0 639 language codes(eg: en, ml, hi, fr, ta etc)
+
+```javascript
+$.i18n().load( {
+ 'localex' : {
+ 'message-key1' : 'message1' // Message for localex.
+ },
+ 'localey' : {
+ 'message-key1' : 'message1'
+ }
+} );
+```
+
+If we want to load the messages for a specific locale, it can be done like this:
+
+```javascript
+$.i18n().load({
+ 'message-hello': 'Hello World',
+ 'message-welcome': 'Welcome'
+}, 'en');
+```
+
+Note the second argument for the `load` method. It should be a valid language code.
+
+It is also possible to refer messages from an external URL. See below example
+
+```javascript
+$.i18n().load( {
+ en: {
+ message_hello: 'Hello World',
+ message_welcome: 'Welcome'
+ },
+ hi: 'i18n/messages-hi.json', // Messages for Hindi
+ de: 'i18n/messages-de.json'
+} );
+```
+
+Messages for a locale can be also loaded in parts. Example
+
+```javascript
+$.i18n().load( {
+ en: {
+ message_hello: 'Hello World',
+ message_welcome: 'Welcome'
+ }
+} );
+
+$.i18n().load( {
+ // This does not remove the previous messages.
+ en: {
+ 'message_header' : 'Header',
+ 'message_footer' : 'Footer',
+ // This will overwrite message_welcome message
+ 'message_welcome' : 'Welcome back'
+ }
+} );
+```
+
+Since it is desirable to render interface messages instantly and not after a delay of loading the message files from a server, make sure that the messages are present at client side before using jQuery.i18n.
+
+The library should expose an API to load an object containing key-value pair of messages. Example: ```$.i18n.load(data)```. This will return a ```jQuery.Promise```.
+
+jquery.i18n plugin
+=========================
+
+The jQuery plugin defines ```$.i18n()``` and ```$.fn.i18n()```
+
+```javascript
+$.i18n( 'message-key-sample1' );
+$.i18n( 'message-key-sample1' );
+$.i18n( 'Found $1 {{plural:$1|result|results}}', 10 ); // Message key itself is message text
+$.i18n( 'Showing $1 out of $2 {{plural:$2|result|results}}', 5,100 );
+$.i18n(' User X updated {{gender|his|her}} profile', 'male' );
+
+$( '#foo' ).i18n(); // to translate the element matching jquery selector based on data-i18n key
+```
+
+Data API
+--------
+
+It is possible to display localized messages without any custom JavaScript. For the HTML tags, add an attribute data-i18n with value as the message key. Example:
+```html
+<li data-i18n="message-key"></li>.
+```
+
+It is also possible to have the above li node with fallback text already in place.
+```html
+<li data-i18n="message-key">Fallback text</li>
+```
+
+The framework will place the localized message corresponding to message-key as the text value of the node. Similar to $('selector').i18n( ... ).
+This will not work for dynamically created elements.
+
+Note that if data-i18n contains html markup, that html will not be used as the element content, instead, the text version will be used. $.fn.i18n is always about replacing text of the element. If you want to change the html of the element, you may want to use: ```$(selector).html($.i18n(messagekey))```
+
+Examples
+========
+
+See http://thottingal.in/projects/js/jquery.i18n/demo/
+
+Message format
+==============
+
+## Placeholders
+
+Messages take parameters. They are represented by $1, $2, $3, … in the message texts, and replaced at run time. Typical parameter values are numbers (Example: "Delete 3 versions?"), or user names (Example: "Page last edited by $1"), page names, links, and so on, or sometimes other messages.
+
+```javascript
+var message = "Welcome, $1";
+$.i18n(message, 'Alice'); // This gives "Welcome, Alice"
+```
+
+
+## Plurals
+
+To make the syntax of sentence correct, plural forms are required. jquery.i18n support plural forms in the message using the syntax `{{PLURAL:$1|pluralform1|pluralform2|...}}`
+
+For example:
+
+```javascript
+var message = "Found $1 {{PLURAL:$1|result|results}}";
+$.i18n(message, 1); // This gives "Found 1 result"
+$.i18n(message, 4); // This gives "Found 4 results"
+```
+Note that {{PLURAL:...}} is not case sensitive. It can be {{plural:...}} too.
+
+In case of English, there are only 2 plural forms, but many languages use more than 2 plural forms. All the plural forms can be given in the above syntax, separated by pipe(|)
+
+## Gender
+Similar to plural, depending on gender of placeholders, mostly user names, the syntax changes dynamically. An example in English is "Alice changed her profile picture" and "Bob changed his profile picture". To support this {{GENDER...}} syntax can be used as show in example
+
+```javascript
+var message = "$1 changed {{GENDER:$2|his|her}} profile picture";
+$.i18n(message, 'Alice', 'female' ); // This gives "Alice changed her profile picture"
+$.i18n(message, 'Bob', 'male' ); // This gives "Bob changed his profile picture"
+```
+
+Note that {{GENDER:...}} is not case sensitive. It can be {{gender:...}} too.
+
+## Grammar
+
+
+```javascript
+$.i18n( { locale: 'fi' } );
+
+var message = "{{grammar:genitive|$1}}";
+
+$.i18n(message, 'talo' ); // This gives "talon"
+
+$.i18n().locale = 'hy'; // Switch to locale Armenian
+$.i18n(message, 'Մաունա'); // This gives "Մաունայի"
+```
+
+## Directionality-safe isolation
+
+To avoid BIDI corruption that looks like "(Foo_(Bar", which happens when a string is inserted into a context with the reverse directionality, you can use `{{bidi:…}}`. Directionality-neutral characters at the edge of the string can get wrongly interpreted by the BIDI algorithm. This would let you embed your substituted string into a new BIDI context, //e.g.//:
+
+ "`Shalom, {{bidi:$1}}, hi!`"
+
+The embedded context's directionality is determined by looking at the argument for `$1`, and then explicitly inserted into the Unicode text, ensuring correct rendering (because then the bidi algorithm "knows" the argument text is a separate context).
+
+
+Fallback
+========
+
+The plugin takes an option 'fallback' with the default value 'en'. The library reuses the fallback data available in MediaWiki for calculating the language fallbacks. Fallbacks are used when a message key is not found in a locale. Example fallbacks: sa->hi->en or tt->tt-cyrl->ru.
+
+See jquery.i18n.fallbacks.js in the source.
+
+Magic word support
+===================
+* For plural, gender and grammar support, MediaWiki template-like syntax - {{...}} will be used.
+* There will be a default implementation for all these in $.i18n.language['default']
+* The plural, gender and grammar methods in ```$.i18n.language[ 'default' ]``` can be overridden or extended in ```$.i18n.language['languageCode']```.
+* Language-specific rules about Gender and Grammar can be written in languages/langXYZ.js files
+* Plural forms will be dynamically calculated using the CLDR plural parser.
+
+Extending the parser
+--------------------
+Following example illustrates extending the parser to support more magic words
+
+```javascript
+$.extend( $.i18n.parser.emitter, {
+ // Handle SITENAME keywords
+ sitename: function () {
+ return 'Wikipedia';
+ },
+ // Handle LINK keywords
+ link: function ( nodes ) {
+ return '<a href="' + nodes[1] + '">' + nodes[0] + '</a>';
+ }
+} );
+```
+
+This will parse the message
+```javascript
+$.i18n( '{{link:{{SITENAME}}|http://en.wikipedia.org}}' );
+```
+
+to
+
+```html
+<a href="http://en.wikipedia.org">Wikipedia</a>
+```
+
+Message documentation
+=====================
+
+The message keys and messages won't give a enough context about the message being translated to the translator. Whenever a developer adds a new message, it is a usual practice to document the message to a file named qqq.json
+with same message key.
+
+Example qqq.json:
+```json
+{
+ "@metadata": {
+ "authors": [
+ "Developer Name"
+ ]
+ },
+ "appname-title": "Application name. Transliteration is recommended",
+ "appname-sub-title": "Brief explanation of the application",
+ "appname-header-introduction": "Text for the introduction header",
+ "appname-about": "About this application text",
+ "appname-footer": "Footer text"
+}
+
+```
+
+In MediaWiki and its hundreds of extensions, message documentation is a strictly followed practice. There is a grunt task to check whether all messages are documented or not. See https://www.npmjs.org/package/grunt-banana-checker
diff --git a/resources/lib/jquery.i18n/src/jquery.i18n.emitter.bidi.js b/resources/lib/jquery.i18n/src/jquery.i18n.emitter.bidi.js
new file mode 100644
index 00000000..3a5b6251
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/jquery.i18n.emitter.bidi.js
@@ -0,0 +1,88 @@
+/**
+ * BIDI embedding support for jQuery.i18n
+ *
+ * Copyright (C) 2015, David Chan
+ *
+ * This code is dual licensed GPLv2 or later and MIT. You don't have to do
+ * anything special to choose one license or the other and you don't have to
+ * notify anyone which license you are using. You are free to use this code
+ * in commercial projects as long as the copyright header is left intact.
+ * See files GPL-LICENSE and MIT-LICENSE for details.
+ *
+ * @licence GNU General Public Licence 2.0 or later
+ * @licence MIT License
+ */
+
+( function ( $ ) {
+ 'use strict';
+ var strongDirRegExp;
+
+ /**
+ * Matches the first strong directionality codepoint:
+ * - in group 1 if it is LTR
+ * - in group 2 if it is RTL
+ * Does not match if there is no strong directionality codepoint.
+ *
+ * Generated by UnicodeJS (see tools/strongDir) from the UCD; see
+ * https://git.wikimedia.org/summary/unicodejs.git .
+ */
+ strongDirRegExp = new RegExp(
+ '(?:' +
+ '(' +
+ '[\u0041-\u005a\u0061-\u007a\u00aa\u00b5\u00ba\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02b8\u02bb-\u02c1\u02d0\u02d1\u02e0-\u02e4\u02ee\u0370-\u0373\u0376\u0377\u037a-\u037d\u037f\u0386\u0388-\u038a\u038c\u038e-\u03a1\u03a3-\u03f5\u03f7-\u0482\u048a-\u052f\u0531-\u0556\u0559-\u055f\u0561-\u0587\u0589\u0903-\u0939\u093b\u093d-\u0940\u0949-\u094c\u094e-\u0950\u0958-\u0961\u0964-\u0980\u0982\u0983\u0985-\u098c\u098f\u0990\u0993-\u09a8\u09aa-\u09b0\u09b2\u09b6-\u09b9\u09bd-\u09c0\u09c7\u09c8\u09cb\u09cc\u09ce\u09d7\u09dc\u09dd\u09df-\u09e1\u09e6-\u09f1\u09f4-\u09fa\u0a03\u0a05-\u0a0a\u0a0f\u0a10\u0a13-\u0a28\u0a2a-\u0a30\u0a32\u0a33\u0a35\u0a36\u0a38\u0a39\u0a3e-\u0a40\u0a59-\u0a5c\u0a5e\u0a66-\u0a6f\u0a72-\u0a74\u0a83\u0a85-\u0a8d\u0a8f-\u0a91\u0a93-\u0aa8\u0aaa-\u0ab0\u0ab2\u0ab3\u0ab5-\u0ab9\u0abd-\u0ac0\u0ac9\u0acb\u0acc\u0ad0\u0ae0\u0ae1\u0ae6-\u0af0\u0af9\u0b02\u0b03\u0b05-\u0b0c\u0b0f\u0b10\u0b13-\u0b28\u0b2a-\u0b30\u0b32\u0b33\u0b35-\u0b39\u0b3d\u0b3e\u0b40\u0b47\u0b48\u0b4b\u0b4c\u0b57\u0b5c\u0b5d\u0b5f-\u0b61\u0b66-\u0b77\u0b83\u0b85-\u0b8a\u0b8e-\u0b90\u0b92-\u0b95\u0b99\u0b9a\u0b9c\u0b9e\u0b9f\u0ba3\u0ba4\u0ba8-\u0baa\u0bae-\u0bb9\u0bbe\u0bbf\u0bc1\u0bc2\u0bc6-\u0bc8\u0bca-\u0bcc\u0bd0\u0bd7\u0be6-\u0bf2\u0c01-\u0c03\u0c05-\u0c0c\u0c0e-\u0c10\u0c12-\u0c28\u0c2a-\u0c39\u0c3d\u0c41-\u0c44\u0c58-\u0c5a\u0c60\u0c61\u0c66-\u0c6f\u0c7f\u0c82\u0c83\u0c85-\u0c8c\u0c8e-\u0c90\u0c92-\u0ca8\u0caa-\u0cb3\u0cb5-\u0cb9\u0cbd-\u0cc4\u0cc6-\u0cc8\u0cca\u0ccb\u0cd5\u0cd6\u0cde\u0ce0\u0ce1\u0ce6-\u0cef\u0cf1\u0cf2\u0d02\u0d03\u0d05-\u0d0c\u0d0e-\u0d10\u0d12-\u0d3a\u0d3d-\u0d40\u0d46-\u0d48\u0d4a-\u0d4c\u0d4e\u0d57\u0d5f-\u0d61\u0d66-\u0d75\u0d79-\u0d7f\u0d82\u0d83\u0d85-\u0d96\u0d9a-\u0db1\u0db3-\u0dbb\u0dbd\u0dc0-\u0dc6\u0dcf-\u0dd1\u0dd8-\u0ddf\u0de6-\u0def\u0df2-\u0df4\u0e01-\u0e30\u0e32\u0e33\u0e40-\u0e46\u0e4f-\u0e5b\u0e81\u0e82\u0e84\u0e87\u0e88\u0e8a\u0e8d\u0e94-\u0e97\u0e99-\u0e9f\u0ea1-\u0ea3\u0ea5\u0ea7\u0eaa\u0eab\u0ead-\u0eb0\u0eb2\u0eb3\u0ebd\u0ec0-\u0ec4\u0ec6\u0ed0-\u0ed9\u0edc-\u0edf\u0f00-\u0f17\u0f1a-\u0f34\u0f36\u0f38\u0f3e-\u0f47\u0f49-\u0f6c\u0f7f\u0f85\u0f88-\u0f8c\u0fbe-\u0fc5\u0fc7-\u0fcc\u0fce-\u0fda\u1000-\u102c\u1031\u1038\u103b\u103c\u103f-\u1057\u105a-\u105d\u1061-\u1070\u1075-\u1081\u1083\u1084\u1087-\u108c\u108e-\u109c\u109e-\u10c5\u10c7\u10cd\u10d0-\u1248\u124a-\u124d\u1250-\u1256\u1258\u125a-\u125d\u1260-\u1288\u128a-\u128d\u1290-\u12b0\u12b2-\u12b5\u12b8-\u12be\u12c0\u12c2-\u12c5\u12c8-\u12d6\u12d8-\u1310\u1312-\u1315\u1318-\u135a\u1360-\u137c\u1380-\u138f\u13a0-\u13f5\u13f8-\u13fd\u1401-\u167f\u1681-\u169a\u16a0-\u16f8\u1700-\u170c\u170e-\u1711\u1720-\u1731\u1735\u1736\u1740-\u1751\u1760-\u176c\u176e-\u1770\u1780-\u17b3\u17b6\u17be-\u17c5\u17c7\u17c8\u17d4-\u17da\u17dc\u17e0-\u17e9\u1810-\u1819\u1820-\u1877\u1880-\u18a8\u18aa\u18b0-\u18f5\u1900-\u191e\u1923-\u1926\u1929-\u192b\u1930\u1931\u1933-\u1938\u1946-\u196d\u1970-\u1974\u1980-\u19ab\u19b0-\u19c9\u19d0-\u19da\u1a00-\u1a16\u1a19\u1a1a\u1a1e-\u1a55\u1a57\u1a61\u1a63\u1a64\u1a6d-\u1a72\u1a80-\u1a89\u1a90-\u1a99\u1aa0-\u1aad\u1b04-\u1b33\u1b35\u1b3b\u1b3d-\u1b41\u1b43-\u1b4b\u1b50-\u1b6a\u1b74-\u1b7c\u1b82-\u1ba1\u1ba6\u1ba7\u1baa\u1bae-\u1be5\u1be7\u1bea-\u1bec\u1bee\u1bf2\u1bf3\u1bfc-\u1c2b\u1c34\u1c35\u1c3b-\u1c49\u1c4d-\u1c7f\u1cc0-\u1cc7\u1cd3\u1ce1\u1ce9-\u1cec\u1cee-\u1cf3\u1cf5\u1cf6\u1d00-\u1dbf\u1e00-\u1f15\u1f18-\u1f1d\u1f20-\u1f45\u1f48-\u1f4d\u1f50-\u1f57\u1f59\u1f5b\u1f5d\u1f5f-\u1f7d\u1f80-\u1fb4\u1fb6-\u1fbc\u1fbe\u1fc2-\u1fc4\u1fc6-\u1fcc\u1fd0-\u1fd3\u1fd6-\u1fdb\u1fe0-\u1fec\u1ff2-\u1ff4\u1ff6-\u1ffc\u200e\u2071\u207f\u2090-\u209c\u2102\u2107\u210a-\u2113\u2115\u2119-\u211d\u2124\u2126\u2128\u212a-\u212d\u212f-\u2139\u213c-\u213f\u2145-\u2149\u214e\u214f\u2160-\u2188\u2336-\u237a\u2395\u249c-\u24e9\u26ac\u2800-\u28ff\u2c00-\u2c2e\u2c30-\u2c5e\u2c60-\u2ce4\u2ceb-\u2cee\u2cf2\u2cf3\u2d00-\u2d25\u2d27\u2d2d\u2d30-\u2d67\u2d6f\u2d70\u2d80-\u2d96\u2da0-\u2da6\u2da8-\u2dae\u2db0-\u2db6\u2db8-\u2dbe\u2dc0-\u2dc6\u2dc8-\u2dce\u2dd0-\u2dd6\u2dd8-\u2dde\u3005-\u3007\u3021-\u3029\u302e\u302f\u3031-\u3035\u3038-\u303c\u3041-\u3096\u309d-\u309f\u30a1-\u30fa\u30fc-\u30ff\u3105-\u312d\u3131-\u318e\u3190-\u31ba\u31f0-\u321c\u3220-\u324f\u3260-\u327b\u327f-\u32b0\u32c0-\u32cb\u32d0-\u32fe\u3300-\u3376\u337b-\u33dd\u33e0-\u33fe\u3400-\u4db5\u4e00-\u9fd5\ua000-\ua48c\ua4d0-\ua60c\ua610-\ua62b\ua640-\ua66e\ua680-\ua69d\ua6a0-\ua6ef\ua6f2-\ua6f7\ua722-\ua787\ua789-\ua7ad\ua7b0-\ua7b7\ua7f7-\ua801\ua803-\ua805\ua807-\ua80a\ua80c-\ua824\ua827\ua830-\ua837\ua840-\ua873\ua880-\ua8c3\ua8ce-\ua8d9\ua8f2-\ua8fd\ua900-\ua925\ua92e-\ua946\ua952\ua953\ua95f-\ua97c\ua983-\ua9b2\ua9b4\ua9b5\ua9ba\ua9bb\ua9bd-\ua9cd\ua9cf-\ua9d9\ua9de-\ua9e4\ua9e6-\ua9fe\uaa00-\uaa28\uaa2f\uaa30\uaa33\uaa34\uaa40-\uaa42\uaa44-\uaa4b\uaa4d\uaa50-\uaa59\uaa5c-\uaa7b\uaa7d-\uaaaf\uaab1\uaab5\uaab6\uaab9-\uaabd\uaac0\uaac2\uaadb-\uaaeb\uaaee-\uaaf5\uab01-\uab06\uab09-\uab0e\uab11-\uab16\uab20-\uab26\uab28-\uab2e\uab30-\uab65\uab70-\uabe4\uabe6\uabe7\uabe9-\uabec\uabf0-\uabf9\uac00-\ud7a3\ud7b0-\ud7c6\ud7cb-\ud7fb\ue000-\ufa6d\ufa70-\ufad9\ufb00-\ufb06\ufb13-\ufb17\uff21-\uff3a\uff41-\uff5a\uff66-\uffbe\uffc2-\uffc7\uffca-\uffcf\uffd2-\uffd7\uffda-\uffdc]|\ud800[\udc00-\udc0b]|\ud800[\udc0d-\udc26]|\ud800[\udc28-\udc3a]|\ud800\udc3c|\ud800\udc3d|\ud800[\udc3f-\udc4d]|\ud800[\udc50-\udc5d]|\ud800[\udc80-\udcfa]|\ud800\udd00|\ud800\udd02|\ud800[\udd07-\udd33]|\ud800[\udd37-\udd3f]|\ud800[\uddd0-\uddfc]|\ud800[\ude80-\ude9c]|\ud800[\udea0-\uded0]|\ud800[\udf00-\udf23]|\ud800[\udf30-\udf4a]|\ud800[\udf50-\udf75]|\ud800[\udf80-\udf9d]|\ud800[\udf9f-\udfc3]|\ud800[\udfc8-\udfd5]|\ud801[\udc00-\udc9d]|\ud801[\udca0-\udca9]|\ud801[\udd00-\udd27]|\ud801[\udd30-\udd63]|\ud801\udd6f|\ud801[\ude00-\udf36]|\ud801[\udf40-\udf55]|\ud801[\udf60-\udf67]|\ud804\udc00|\ud804[\udc02-\udc37]|\ud804[\udc47-\udc4d]|\ud804[\udc66-\udc6f]|\ud804[\udc82-\udcb2]|\ud804\udcb7|\ud804\udcb8|\ud804[\udcbb-\udcc1]|\ud804[\udcd0-\udce8]|\ud804[\udcf0-\udcf9]|\ud804[\udd03-\udd26]|\ud804\udd2c|\ud804[\udd36-\udd43]|\ud804[\udd50-\udd72]|\ud804[\udd74-\udd76]|\ud804[\udd82-\uddb5]|\ud804[\uddbf-\uddc9]|\ud804\uddcd|\ud804[\uddd0-\udddf]|\ud804[\udde1-\uddf4]|\ud804[\ude00-\ude11]|\ud804[\ude13-\ude2e]|\ud804\ude32|\ud804\ude33|\ud804\ude35|\ud804[\ude38-\ude3d]|\ud804[\ude80-\ude86]|\ud804\ude88|\ud804[\ude8a-\ude8d]|\ud804[\ude8f-\ude9d]|\ud804[\ude9f-\udea9]|\ud804[\udeb0-\udede]|\ud804[\udee0-\udee2]|\ud804[\udef0-\udef9]|\ud804\udf02|\ud804\udf03|\ud804[\udf05-\udf0c]|\ud804\udf0f|\ud804\udf10|\ud804[\udf13-\udf28]|\ud804[\udf2a-\udf30]|\ud804\udf32|\ud804\udf33|\ud804[\udf35-\udf39]|\ud804[\udf3d-\udf3f]|\ud804[\udf41-\udf44]|\ud804\udf47|\ud804\udf48|\ud804[\udf4b-\udf4d]|\ud804\udf50|\ud804\udf57|\ud804[\udf5d-\udf63]|\ud805[\udc80-\udcb2]|\ud805\udcb9|\ud805[\udcbb-\udcbe]|\ud805\udcc1|\ud805[\udcc4-\udcc7]|\ud805[\udcd0-\udcd9]|\ud805[\udd80-\uddb1]|\ud805[\uddb8-\uddbb]|\ud805\uddbe|\ud805[\uddc1-\udddb]|\ud805[\ude00-\ude32]|\ud805\ude3b|\ud805\ude3c|\ud805\ude3e|\ud805[\ude41-\ude44]|\ud805[\ude50-\ude59]|\ud805[\ude80-\udeaa]|\ud805\udeac|\ud805\udeae|\ud805\udeaf|\ud805\udeb6|\ud805[\udec0-\udec9]|\ud805[\udf00-\udf19]|\ud805\udf20|\ud805\udf21|\ud805\udf26|\ud805[\udf30-\udf3f]|\ud806[\udca0-\udcf2]|\ud806\udcff|\ud806[\udec0-\udef8]|\ud808[\udc00-\udf99]|\ud809[\udc00-\udc6e]|\ud809[\udc70-\udc74]|\ud809[\udc80-\udd43]|\ud80c[\udc00-\udfff]|\ud80d[\udc00-\udc2e]|\ud811[\udc00-\ude46]|\ud81a[\udc00-\ude38]|\ud81a[\ude40-\ude5e]|\ud81a[\ude60-\ude69]|\ud81a\ude6e|\ud81a\ude6f|\ud81a[\uded0-\udeed]|\ud81a\udef5|\ud81a[\udf00-\udf2f]|\ud81a[\udf37-\udf45]|\ud81a[\udf50-\udf59]|\ud81a[\udf5b-\udf61]|\ud81a[\udf63-\udf77]|\ud81a[\udf7d-\udf8f]|\ud81b[\udf00-\udf44]|\ud81b[\udf50-\udf7e]|\ud81b[\udf93-\udf9f]|\ud82c\udc00|\ud82c\udc01|\ud82f[\udc00-\udc6a]|\ud82f[\udc70-\udc7c]|\ud82f[\udc80-\udc88]|\ud82f[\udc90-\udc99]|\ud82f\udc9c|\ud82f\udc9f|\ud834[\udc00-\udcf5]|\ud834[\udd00-\udd26]|\ud834[\udd29-\udd66]|\ud834[\udd6a-\udd72]|\ud834\udd83|\ud834\udd84|\ud834[\udd8c-\udda9]|\ud834[\uddae-\udde8]|\ud834[\udf60-\udf71]|\ud835[\udc00-\udc54]|\ud835[\udc56-\udc9c]|\ud835\udc9e|\ud835\udc9f|\ud835\udca2|\ud835\udca5|\ud835\udca6|\ud835[\udca9-\udcac]|\ud835[\udcae-\udcb9]|\ud835\udcbb|\ud835[\udcbd-\udcc3]|\ud835[\udcc5-\udd05]|\ud835[\udd07-\udd0a]|\ud835[\udd0d-\udd14]|\ud835[\udd16-\udd1c]|\ud835[\udd1e-\udd39]|\ud835[\udd3b-\udd3e]|\ud835[\udd40-\udd44]|\ud835\udd46|\ud835[\udd4a-\udd50]|\ud835[\udd52-\udea5]|\ud835[\udea8-\udeda]|\ud835[\udedc-\udf14]|\ud835[\udf16-\udf4e]|\ud835[\udf50-\udf88]|\ud835[\udf8a-\udfc2]|\ud835[\udfc4-\udfcb]|\ud836[\udc00-\uddff]|\ud836[\ude37-\ude3a]|\ud836[\ude6d-\ude74]|\ud836[\ude76-\ude83]|\ud836[\ude85-\ude8b]|\ud83c[\udd10-\udd2e]|\ud83c[\udd30-\udd69]|\ud83c[\udd70-\udd9a]|\ud83c[\udde6-\ude02]|\ud83c[\ude10-\ude3a]|\ud83c[\ude40-\ude48]|\ud83c\ude50|\ud83c\ude51|[\ud840-\ud868][\udc00-\udfff]|\ud869[\udc00-\uded6]|\ud869[\udf00-\udfff]|[\ud86a-\ud86c][\udc00-\udfff]|\ud86d[\udc00-\udf34]|\ud86d[\udf40-\udfff]|\ud86e[\udc00-\udc1d]|\ud86e[\udc20-\udfff]|[\ud86f-\ud872][\udc00-\udfff]|\ud873[\udc00-\udea1]|\ud87e[\udc00-\ude1d]|[\udb80-\udbbe][\udc00-\udfff]|\udbbf[\udc00-\udffd]|[\udbc0-\udbfe][\udc00-\udfff]|\udbff[\udc00-\udffd]' +
+ ')|(' +
+ '[\u0590\u05be\u05c0\u05c3\u05c6\u05c8-\u05ff\u07c0-\u07ea\u07f4\u07f5\u07fa-\u0815\u081a\u0824\u0828\u082e-\u0858\u085c-\u089f\u200f\ufb1d\ufb1f-\ufb28\ufb2a-\ufb4f\u0608\u060b\u060d\u061b-\u064a\u066d-\u066f\u0671-\u06d5\u06e5\u06e6\u06ee\u06ef\u06fa-\u0710\u0712-\u072f\u074b-\u07a5\u07b1-\u07bf\u08a0-\u08e2\ufb50-\ufd3d\ufd40-\ufdcf\ufdf0-\ufdfc\ufdfe\ufdff\ufe70-\ufefe]|\ud802[\udc00-\udd1e]|\ud802[\udd20-\ude00]|\ud802\ude04|\ud802[\ude07-\ude0b]|\ud802[\ude10-\ude37]|\ud802[\ude3b-\ude3e]|\ud802[\ude40-\udee4]|\ud802[\udee7-\udf38]|\ud802[\udf40-\udfff]|\ud803[\udc00-\ude5f]|\ud803[\ude7f-\udfff]|\ud83a[\udc00-\udccf]|\ud83a[\udcd7-\udfff]|\ud83b[\udc00-\uddff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\udf00-\udfff]|\ud83b[\ude00-\udeef]|\ud83b[\udef2-\udeff]' +
+ ')' +
+ ')'
+ );
+
+ /**
+ * Gets directionality of the first strongly directional codepoint
+ *
+ * This is the rule the BIDI algorithm uses to determine the directionality of
+ * paragraphs ( http://unicode.org/reports/tr9/#The_Paragraph_Level ) and
+ * FSI isolates ( http://unicode.org/reports/tr9/#Explicit_Directional_Isolates ).
+ *
+ * TODO: Does not handle BIDI control characters inside the text.
+ * TODO: Does not handle unallocated characters.
+ */
+ function strongDirFromContent( text ) {
+ var m = text.match( strongDirRegExp );
+ if ( !m ) {
+ return null;
+ }
+ if ( m[2] === undefined ) {
+ return 'ltr';
+ }
+ return 'rtl';
+ }
+
+ $.extend( $.i18n.parser.emitter, {
+ /**
+ * Wraps argument with unicode control characters for directionality safety
+ *
+ * This solves the problem where directionality-neutral characters at the edge of
+ * the argument string get interpreted with the wrong directionality from the
+ * enclosing context, giving renderings that look corrupted like "(Ben_(WMF".
+ *
+ * The wrapping is LRE...PDF or RLE...PDF, depending on the detected
+ * directionality of the argument string, using the BIDI algorithm's own "First
+ * strong directional codepoint" rule. Essentially, this works round the fact that
+ * there is no embedding equivalent of U+2068 FSI (isolation with heuristic
+ * direction inference). The latter is cleaner but still not widely supported.
+ */
+ bidi: function ( nodes ) {
+ var dir = strongDirFromContent( nodes[0] );
+ if ( dir === 'ltr' ) {
+ // Wrap in LEFT-TO-RIGHT EMBEDDING ... POP DIRECTIONAL FORMATTING
+ return '\u202A' + nodes[0] + '\u202C';
+ }
+ if ( dir === 'rtl' ) {
+ // Wrap in RIGHT-TO-LEFT EMBEDDING ... POP DIRECTIONAL FORMATTING
+ return '\u202B' + nodes[0] + '\u202C';
+ }
+ // No strong directionality: do not wrap
+ return nodes[0];
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/jquery.i18n.emitter.js b/resources/lib/jquery.i18n/src/jquery.i18n.emitter.js
new file mode 100644
index 00000000..b26f147d
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/jquery.i18n.emitter.js
@@ -0,0 +1,168 @@
+/**
+ * jQuery Internationalization library
+ *
+ * Copyright (C) 2011-2013 Santhosh Thottingal, Neil Kandalgaonkar
+ *
+ * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do
+ * anything special to choose one license or the other and you don't have to
+ * notify anyone which license you are using. You are free to use
+ * UniversalLanguageSelector in commercial projects as long as the copyright
+ * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
+ *
+ * @licence GNU General Public Licence 2.0 or later
+ * @licence MIT License
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ var MessageParserEmitter = function () {
+ this.language = $.i18n.languages[String.locale] || $.i18n.languages['default'];
+ };
+
+ MessageParserEmitter.prototype = {
+ constructor: MessageParserEmitter,
+
+ /**
+ * (We put this method definition here, and not in prototype, to make
+ * sure it's not overwritten by any magic.) Walk entire node structure,
+ * applying replacements and template functions when appropriate
+ *
+ * @param {Mixed} node abstract syntax tree (top node or subnode)
+ * @param {Array} replacements for $1, $2, ... $n
+ * @return {Mixed} single-string node or array of nodes suitable for
+ * jQuery appending.
+ */
+ emit: function ( node, replacements ) {
+ var ret, subnodes, operation,
+ messageParserEmitter = this;
+
+ switch ( typeof node ) {
+ case 'string':
+ case 'number':
+ ret = node;
+ break;
+ case 'object':
+ // node is an array of nodes
+ subnodes = $.map( node.slice( 1 ), function ( n ) {
+ return messageParserEmitter.emit( n, replacements );
+ } );
+
+ operation = node[0].toLowerCase();
+
+ if ( typeof messageParserEmitter[operation] === 'function' ) {
+ ret = messageParserEmitter[operation]( subnodes, replacements );
+ } else {
+ throw new Error( 'unknown operation "' + operation + '"' );
+ }
+
+ break;
+ case 'undefined':
+ // Parsing the empty string (as an entire expression, or as a
+ // paramExpression in a template) results in undefined
+ // Perhaps a more clever parser can detect this, and return the
+ // empty string? Or is that useful information?
+ // The logical thing is probably to return the empty string here
+ // when we encounter undefined.
+ ret = '';
+ break;
+ default:
+ throw new Error( 'unexpected type in AST: ' + typeof node );
+ }
+
+ return ret;
+ },
+
+ /**
+ * Parsing has been applied depth-first we can assume that all nodes
+ * here are single nodes Must return a single node to parents -- a
+ * jQuery with synthetic span However, unwrap any other synthetic spans
+ * in our children and pass them upwards
+ *
+ * @param {Array} nodes Mixed, some single nodes, some arrays of nodes.
+ * @return String
+ */
+ concat: function ( nodes ) {
+ var result = '';
+
+ $.each( nodes, function ( i, node ) {
+ // strings, integers, anything else
+ result += node;
+ } );
+
+ return result;
+ },
+
+ /**
+ * Return escaped replacement of correct index, or string if
+ * unavailable. Note that we expect the parsed parameter to be
+ * zero-based. i.e. $1 should have become [ 0 ]. if the specified
+ * parameter is not found return the same string (e.g. "$99" ->
+ * parameter 98 -> not found -> return "$99" ) TODO throw error if
+ * nodes.length > 1 ?
+ *
+ * @param {Array} nodes One element, integer, n >= 0
+ * @param {Array} replacements for $1, $2, ... $n
+ * @return {string} replacement
+ */
+ replace: function ( nodes, replacements ) {
+ var index = parseInt( nodes[0], 10 );
+
+ if ( index < replacements.length ) {
+ // replacement is not a string, don't touch!
+ return replacements[index];
+ } else {
+ // index not found, fallback to displaying variable
+ return '$' + ( index + 1 );
+ }
+ },
+
+ /**
+ * Transform parsed structure into pluralization n.b. The first node may
+ * be a non-integer (for instance, a string representing an Arabic
+ * number). So convert it back with the current language's
+ * convertNumber.
+ *
+ * @param {Array} nodes List [ {String|Number}, {String}, {String} ... ]
+ * @return {String} selected pluralized form according to current
+ * language.
+ */
+ plural: function ( nodes ) {
+ var count = parseFloat( this.language.convertNumber( nodes[0], 10 ) ),
+ forms = nodes.slice( 1 );
+
+ return forms.length ? this.language.convertPlural( count, forms ) : '';
+ },
+
+ /**
+ * Transform parsed structure into gender Usage
+ * {{gender:gender|masculine|feminine|neutral}}.
+ *
+ * @param {Array} nodes List [ {String}, {String}, {String} , {String} ]
+ * @return {String} selected gender form according to current language
+ */
+ gender: function ( nodes ) {
+ var gender = nodes[0],
+ forms = nodes.slice( 1 );
+
+ return this.language.gender( gender, forms );
+ },
+
+ /**
+ * Transform parsed structure into grammar conversion. Invoked by
+ * putting {{grammar:form|word}} in a message
+ *
+ * @param {Array} nodes List [{Grammar case eg: genitive}, {String word}]
+ * @return {String} selected grammatical form according to current
+ * language.
+ */
+ grammar: function ( nodes ) {
+ var form = nodes[0],
+ word = nodes[1];
+
+ return word && form && this.language.convertGrammar( word, form );
+ }
+ };
+
+ $.extend( $.i18n.parser.emitter, new MessageParserEmitter() );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/jquery.i18n.fallbacks.js b/resources/lib/jquery.i18n/src/jquery.i18n.fallbacks.js
new file mode 100644
index 00000000..4584c5f2
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/jquery.i18n.fallbacks.js
@@ -0,0 +1,186 @@
+/**
+ * jQuery Internationalization library
+ *
+ * Copyright (C) 2012 Santhosh Thottingal
+ *
+ * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do anything special to
+ * choose one license or the other and you don't have to notify anyone which license you are using.
+ * You are free to use UniversalLanguageSelector in commercial projects as long as the copyright
+ * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
+ *
+ * @licence GNU General Public Licence 2.0 or later
+ * @licence MIT License
+ */
+( function ( $, undefined ) {
+ 'use strict';
+
+ $.i18n = $.i18n || {};
+ $.extend( $.i18n.fallbacks, {
+ ab: [ 'ru' ],
+ ace: [ 'id' ],
+ aln: [ 'sq' ],
+ // Not so standard - als is supposed to be Tosk Albanian,
+ // but in Wikipedia it's used for a Germanic language.
+ als: [ 'gsw', 'de' ],
+ an: [ 'es' ],
+ anp: [ 'hi' ],
+ arn: [ 'es' ],
+ arz: [ 'ar' ],
+ av: [ 'ru' ],
+ ay: [ 'es' ],
+ ba: [ 'ru' ],
+ bar: [ 'de' ],
+ 'bat-smg': [ 'sgs', 'lt' ],
+ bcc: [ 'fa' ],
+ 'be-x-old': [ 'be-tarask' ],
+ bh: [ 'bho' ],
+ bjn: [ 'id' ],
+ bm: [ 'fr' ],
+ bpy: [ 'bn' ],
+ bqi: [ 'fa' ],
+ bug: [ 'id' ],
+ 'cbk-zam': [ 'es' ],
+ ce: [ 'ru' ],
+ crh: [ 'crh-latn' ],
+ 'crh-cyrl': [ 'ru' ],
+ csb: [ 'pl' ],
+ cv: [ 'ru' ],
+ 'de-at': [ 'de' ],
+ 'de-ch': [ 'de' ],
+ 'de-formal': [ 'de' ],
+ dsb: [ 'de' ],
+ dtp: [ 'ms' ],
+ egl: [ 'it' ],
+ eml: [ 'it' ],
+ ff: [ 'fr' ],
+ fit: [ 'fi' ],
+ 'fiu-vro': [ 'vro', 'et' ],
+ frc: [ 'fr' ],
+ frp: [ 'fr' ],
+ frr: [ 'de' ],
+ fur: [ 'it' ],
+ gag: [ 'tr' ],
+ gan: [ 'gan-hant', 'zh-hant', 'zh-hans' ],
+ 'gan-hans': [ 'zh-hans' ],
+ 'gan-hant': [ 'zh-hant', 'zh-hans' ],
+ gl: [ 'pt' ],
+ glk: [ 'fa' ],
+ gn: [ 'es' ],
+ gsw: [ 'de' ],
+ hif: [ 'hif-latn' ],
+ hsb: [ 'de' ],
+ ht: [ 'fr' ],
+ ii: [ 'zh-cn', 'zh-hans' ],
+ inh: [ 'ru' ],
+ iu: [ 'ike-cans' ],
+ jut: [ 'da' ],
+ jv: [ 'id' ],
+ kaa: [ 'kk-latn', 'kk-cyrl' ],
+ kbd: [ 'kbd-cyrl' ],
+ khw: [ 'ur' ],
+ kiu: [ 'tr' ],
+ kk: [ 'kk-cyrl' ],
+ 'kk-arab': [ 'kk-cyrl' ],
+ 'kk-latn': [ 'kk-cyrl' ],
+ 'kk-cn': [ 'kk-arab', 'kk-cyrl' ],
+ 'kk-kz': [ 'kk-cyrl' ],
+ 'kk-tr': [ 'kk-latn', 'kk-cyrl' ],
+ kl: [ 'da' ],
+ 'ko-kp': [ 'ko' ],
+ koi: [ 'ru' ],
+ krc: [ 'ru' ],
+ ks: [ 'ks-arab' ],
+ ksh: [ 'de' ],
+ ku: [ 'ku-latn' ],
+ 'ku-arab': [ 'ckb' ],
+ kv: [ 'ru' ],
+ lad: [ 'es' ],
+ lb: [ 'de' ],
+ lbe: [ 'ru' ],
+ lez: [ 'ru' ],
+ li: [ 'nl' ],
+ lij: [ 'it' ],
+ liv: [ 'et' ],
+ lmo: [ 'it' ],
+ ln: [ 'fr' ],
+ ltg: [ 'lv' ],
+ lzz: [ 'tr' ],
+ mai: [ 'hi' ],
+ 'map-bms': [ 'jv', 'id' ],
+ mg: [ 'fr' ],
+ mhr: [ 'ru' ],
+ min: [ 'id' ],
+ mo: [ 'ro' ],
+ mrj: [ 'ru' ],
+ mwl: [ 'pt' ],
+ myv: [ 'ru' ],
+ mzn: [ 'fa' ],
+ nah: [ 'es' ],
+ nap: [ 'it' ],
+ nds: [ 'de' ],
+ 'nds-nl': [ 'nl' ],
+ 'nl-informal': [ 'nl' ],
+ no: [ 'nb' ],
+ os: [ 'ru' ],
+ pcd: [ 'fr' ],
+ pdc: [ 'de' ],
+ pdt: [ 'de' ],
+ pfl: [ 'de' ],
+ pms: [ 'it' ],
+ pt: [ 'pt-br' ],
+ 'pt-br': [ 'pt' ],
+ qu: [ 'es' ],
+ qug: [ 'qu', 'es' ],
+ rgn: [ 'it' ],
+ rmy: [ 'ro' ],
+ 'roa-rup': [ 'rup' ],
+ rue: [ 'uk', 'ru' ],
+ ruq: [ 'ruq-latn', 'ro' ],
+ 'ruq-cyrl': [ 'mk' ],
+ 'ruq-latn': [ 'ro' ],
+ sa: [ 'hi' ],
+ sah: [ 'ru' ],
+ scn: [ 'it' ],
+ sg: [ 'fr' ],
+ sgs: [ 'lt' ],
+ sli: [ 'de' ],
+ sr: [ 'sr-ec' ],
+ srn: [ 'nl' ],
+ stq: [ 'de' ],
+ su: [ 'id' ],
+ szl: [ 'pl' ],
+ tcy: [ 'kn' ],
+ tg: [ 'tg-cyrl' ],
+ tt: [ 'tt-cyrl', 'ru' ],
+ 'tt-cyrl': [ 'ru' ],
+ ty: [ 'fr' ],
+ udm: [ 'ru' ],
+ ug: [ 'ug-arab' ],
+ uk: [ 'ru' ],
+ vec: [ 'it' ],
+ vep: [ 'et' ],
+ vls: [ 'nl' ],
+ vmf: [ 'de' ],
+ vot: [ 'fi' ],
+ vro: [ 'et' ],
+ wa: [ 'fr' ],
+ wo: [ 'fr' ],
+ wuu: [ 'zh-hans' ],
+ xal: [ 'ru' ],
+ xmf: [ 'ka' ],
+ yi: [ 'he' ],
+ za: [ 'zh-hans' ],
+ zea: [ 'nl' ],
+ zh: [ 'zh-hans' ],
+ 'zh-classical': [ 'lzh' ],
+ 'zh-cn': [ 'zh-hans' ],
+ 'zh-hant': [ 'zh-hans' ],
+ 'zh-hk': [ 'zh-hant', 'zh-hans' ],
+ 'zh-min-nan': [ 'nan' ],
+ 'zh-mo': [ 'zh-hk', 'zh-hant', 'zh-hans' ],
+ 'zh-my': [ 'zh-sg', 'zh-hans' ],
+ 'zh-sg': [ 'zh-hans' ],
+ 'zh-tw': [ 'zh-hant', 'zh-hans' ],
+ 'zh-yue': [ 'yue' ]
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/jquery.i18n.js b/resources/lib/jquery.i18n/src/jquery.i18n.js
new file mode 100644
index 00000000..9236e4e2
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/jquery.i18n.js
@@ -0,0 +1,287 @@
+/**
+ * jQuery Internationalization library
+ *
+ * Copyright (C) 2012 Santhosh Thottingal
+ *
+ * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do
+ * anything special to choose one license or the other and you don't have to
+ * notify anyone which license you are using. You are free to use
+ * UniversalLanguageSelector in commercial projects as long as the copyright
+ * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
+ *
+ * @licence GNU General Public Licence 2.0 or later
+ * @licence MIT License
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ var nav, I18N,
+ slice = Array.prototype.slice;
+ /**
+ * @constructor
+ * @param {Object} options
+ */
+ I18N = function ( options ) {
+ // Load defaults
+ this.options = $.extend( {}, I18N.defaults, options );
+
+ this.parser = this.options.parser;
+ this.locale = this.options.locale;
+ this.messageStore = this.options.messageStore;
+ this.languages = {};
+
+ this.init();
+ };
+
+ I18N.prototype = {
+ /**
+ * Initialize by loading locales and setting up
+ * String.prototype.toLocaleString and String.locale.
+ */
+ init: function () {
+ var i18n = this;
+
+ // Set locale of String environment
+ String.locale = i18n.locale;
+
+ // Override String.localeString method
+ String.prototype.toLocaleString = function () {
+ var localeParts, localePartIndex, value, locale, fallbackIndex,
+ tryingLocale, message;
+
+ value = this.valueOf();
+ locale = i18n.locale;
+ fallbackIndex = 0;
+
+ while ( locale ) {
+ // Iterate through locales starting at most-specific until
+ // localization is found. As in fi-Latn-FI, fi-Latn and fi.
+ localeParts = locale.split( '-' );
+ localePartIndex = localeParts.length;
+
+ do {
+ tryingLocale = localeParts.slice( 0, localePartIndex ).join( '-' );
+ message = i18n.messageStore.get( tryingLocale, value );
+
+ if ( message ) {
+ return message;
+ }
+
+ localePartIndex--;
+ } while ( localePartIndex );
+
+ if ( locale === 'en' ) {
+ break;
+ }
+
+ locale = ( $.i18n.fallbacks[i18n.locale] && $.i18n.fallbacks[i18n.locale][fallbackIndex] ) ||
+ i18n.options.fallbackLocale;
+ $.i18n.log( 'Trying fallback locale for ' + i18n.locale + ': ' + locale );
+
+ fallbackIndex++;
+ }
+
+ // key not found
+ return '';
+ };
+ },
+
+ /*
+ * Destroy the i18n instance.
+ */
+ destroy: function () {
+ $.removeData( document, 'i18n' );
+ },
+
+ /**
+ * General message loading API This can take a URL string for
+ * the json formatted messages. Example:
+ * <code>load('path/to/all_localizations.json');</code>
+ *
+ * To load a localization file for a locale:
+ * <code>
+ * load('path/to/de-messages.json', 'de' );
+ * </code>
+ *
+ * To load a localization file from a directory:
+ * <code>
+ * load('path/to/i18n/directory', 'de' );
+ * </code>
+ * The above method has the advantage of fallback resolution.
+ * ie, it will automatically load the fallback locales for de.
+ * For most usecases, this is the recommended method.
+ * It is optional to have trailing slash at end.
+ *
+ * A data object containing message key- message translation mappings
+ * can also be passed. Example:
+ * <code>
+ * load( { 'hello' : 'Hello' }, optionalLocale );
+ * </code>
+ *
+ * A source map containing key-value pair of languagename and locations
+ * can also be passed. Example:
+ * <code>
+ * load( {
+ * bn: 'i18n/bn.json',
+ * he: 'i18n/he.json',
+ * en: 'i18n/en.json'
+ * } )
+ * </code>
+ *
+ * If the data argument is null/undefined/false,
+ * all cached messages for the i18n instance will get reset.
+ *
+ * @param {String|Object} source
+ * @param {String} locale Language tag
+ * @returns {jQuery.Promise}
+ */
+ load: function ( source, locale ) {
+ var fallbackLocales, locIndex, fallbackLocale, sourceMap = {};
+ if ( !source && !locale ) {
+ source = 'i18n/' + $.i18n().locale + '.json';
+ locale = $.i18n().locale;
+ }
+ if ( typeof source === 'string' &&
+ source.split( '.' ).pop() !== 'json'
+ ) {
+ // Load specified locale then check for fallbacks when directory is specified in load()
+ sourceMap[locale] = source + '/' + locale + '.json';
+ fallbackLocales = ( $.i18n.fallbacks[locale] || [] )
+ .concat( this.options.fallbackLocale );
+ for ( locIndex in fallbackLocales ) {
+ fallbackLocale = fallbackLocales[locIndex];
+ sourceMap[fallbackLocale] = source + '/' + fallbackLocale + '.json';
+ }
+ return this.load( sourceMap );
+ } else {
+ return this.messageStore.load( source, locale );
+ }
+
+ },
+
+ /**
+ * Does parameter and magic word substitution.
+ *
+ * @param {string} key Message key
+ * @param {Array} parameters Message parameters
+ * @return {string}
+ */
+ parse: function ( key, parameters ) {
+ var message = key.toLocaleString();
+ // FIXME: This changes the state of the I18N object,
+ // should probably not change the 'this.parser' but just
+ // pass it to the parser.
+ this.parser.language = $.i18n.languages[$.i18n().locale] || $.i18n.languages['default'];
+ if ( message === '' ) {
+ message = key;
+ }
+ return this.parser.parse( message, parameters );
+ }
+ };
+
+ /**
+ * Process a message from the $.I18N instance
+ * for the current document, stored in jQuery.data(document).
+ *
+ * @param {string} key Key of the message.
+ * @param {string} param1 [param...] Variadic list of parameters for {key}.
+ * @return {string|$.I18N} Parsed message, or if no key was given
+ * the instance of $.I18N is returned.
+ */
+ $.i18n = function ( key, param1 ) {
+ var parameters,
+ i18n = $.data( document, 'i18n' ),
+ options = typeof key === 'object' && key;
+
+ // If the locale option for this call is different then the setup so far,
+ // update it automatically. This doesn't just change the context for this
+ // call but for all future call as well.
+ // If there is no i18n setup yet, don't do this. It will be taken care of
+ // by the `new I18N` construction below.
+ // NOTE: It should only change language for this one call.
+ // Then cache instances of I18N somewhere.
+ if ( options && options.locale && i18n && i18n.locale !== options.locale ) {
+ String.locale = i18n.locale = options.locale;
+ }
+
+ if ( !i18n ) {
+ i18n = new I18N( options );
+ $.data( document, 'i18n', i18n );
+ }
+
+ if ( typeof key === 'string' ) {
+ if ( param1 !== undefined ) {
+ parameters = slice.call( arguments, 1 );
+ } else {
+ parameters = [];
+ }
+
+ return i18n.parse( key, parameters );
+ } else {
+ // FIXME: remove this feature/bug.
+ return i18n;
+ }
+ };
+
+ $.fn.i18n = function () {
+ var i18n = $.data( document, 'i18n' );
+
+ if ( !i18n ) {
+ i18n = new I18N();
+ $.data( document, 'i18n', i18n );
+ }
+ String.locale = i18n.locale;
+ return this.each( function () {
+ var $this = $( this ),
+ messageKey = $this.data( 'i18n' );
+
+ if ( messageKey ) {
+ $this.text( i18n.parse( messageKey ) );
+ } else {
+ $this.find( '[data-i18n]' ).i18n();
+ }
+ } );
+ };
+
+ String.locale = String.locale || $( 'html' ).attr( 'lang' );
+
+ if ( !String.locale ) {
+ if ( typeof window.navigator !== undefined ) {
+ nav = window.navigator;
+ String.locale = nav.language || nav.userLanguage || '';
+ } else {
+ String.locale = '';
+ }
+ }
+
+ $.i18n.languages = {};
+ $.i18n.messageStore = $.i18n.messageStore || {};
+ $.i18n.parser = {
+ // The default parser only handles variable substitution
+ parse: function ( message, parameters ) {
+ return message.replace( /\$(\d+)/g, function ( str, match ) {
+ var index = parseInt( match, 10 ) - 1;
+ return parameters[index] !== undefined ? parameters[index] : '$' + match;
+ } );
+ },
+ emitter: {}
+ };
+ $.i18n.fallbacks = {};
+ $.i18n.debug = false;
+ $.i18n.log = function ( /* arguments */ ) {
+ if ( window.console && $.i18n.debug ) {
+ window.console.log.apply( window.console, arguments );
+ }
+ };
+ /* Static members */
+ I18N.defaults = {
+ locale: String.locale,
+ fallbackLocale: 'en',
+ parser: $.i18n.parser,
+ messageStore: $.i18n.messageStore
+ };
+
+ // Expose constructor
+ $.i18n.constructor = I18N;
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/jquery.i18n.language.js b/resources/lib/jquery.i18n/src/jquery.i18n.language.js
new file mode 100644
index 00000000..e596fbc8
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/jquery.i18n.language.js
@@ -0,0 +1,472 @@
+/*global pluralRuleParser */
+( function ( $ ) {
+ 'use strict';
+
+ var language = {
+ // CLDR plural rules generated using
+ // libs/CLDRPluralRuleParser/tools/PluralXML2JSON.html
+ pluralRules: {
+ ak: {
+ one: 'n = 0..1'
+ },
+ am: {
+ one: 'i = 0 or n = 1'
+ },
+ ar: {
+ zero: 'n = 0',
+ one: 'n = 1',
+ two: 'n = 2',
+ few: 'n % 100 = 3..10',
+ many: 'n % 100 = 11..99'
+ },
+ be: {
+ one: 'n % 10 = 1 and n % 100 != 11',
+ few: 'n % 10 = 2..4 and n % 100 != 12..14',
+ many: 'n % 10 = 0 or n % 10 = 5..9 or n % 100 = 11..14'
+ },
+ bh: {
+ one: 'n = 0..1'
+ },
+ bn: {
+ one: 'i = 0 or n = 1'
+ },
+ br: {
+ one: 'n % 10 = 1 and n % 100 != 11,71,91',
+ two: 'n % 10 = 2 and n % 100 != 12,72,92',
+ few: 'n % 10 = 3..4,9 and n % 100 != 10..19,70..79,90..99',
+ many: 'n != 0 and n % 1000000 = 0'
+ },
+ bs: {
+ one: 'v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11',
+ few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14'
+ },
+ cs: {
+ one: 'i = 1 and v = 0',
+ few: 'i = 2..4 and v = 0',
+ many: 'v != 0'
+ },
+ cy: {
+ zero: 'n = 0',
+ one: 'n = 1',
+ two: 'n = 2',
+ few: 'n = 3',
+ many: 'n = 6'
+ },
+ da: {
+ one: 'n = 1 or t != 0 and i = 0,1'
+ },
+ fa: {
+ one: 'i = 0 or n = 1'
+ },
+ ff: {
+ one: 'i = 0,1'
+ },
+ fil: {
+ one: 'i = 0..1 and v = 0'
+ },
+ fr: {
+ one: 'i = 0,1'
+ },
+ ga: {
+ one: 'n = 1',
+ two: 'n = 2',
+ few: 'n = 3..6',
+ many: 'n = 7..10'
+ },
+ gd: {
+ one: 'n = 1,11',
+ two: 'n = 2,12',
+ few: 'n = 3..10,13..19'
+ },
+ gu: {
+ one: 'i = 0 or n = 1'
+ },
+ guw: {
+ one: 'n = 0..1'
+ },
+ gv: {
+ one: 'n % 10 = 1',
+ two: 'n % 10 = 2',
+ few: 'n % 100 = 0,20,40,60'
+ },
+ he: {
+ one: 'i = 1 and v = 0',
+ two: 'i = 2 and v = 0',
+ many: 'v = 0 and n != 0..10 and n % 10 = 0'
+ },
+ hi: {
+ one: 'i = 0 or n = 1'
+ },
+ hr: {
+ one: 'v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11',
+ few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14'
+ },
+ hy: {
+ one: 'i = 0,1'
+ },
+ is: {
+ one: 't = 0 and i % 10 = 1 and i % 100 != 11 or t != 0'
+ },
+ iu: {
+ one: 'n = 1',
+ two: 'n = 2'
+ },
+ iw: {
+ one: 'i = 1 and v = 0',
+ two: 'i = 2 and v = 0',
+ many: 'v = 0 and n != 0..10 and n % 10 = 0'
+ },
+ kab: {
+ one: 'i = 0,1'
+ },
+ kn: {
+ one: 'i = 0 or n = 1'
+ },
+ kw: {
+ one: 'n = 1',
+ two: 'n = 2'
+ },
+ lag: {
+ zero: 'n = 0',
+ one: 'i = 0,1 and n != 0'
+ },
+ ln: {
+ one: 'n = 0..1'
+ },
+ lt: {
+ one: 'n % 10 = 1 and n % 100 != 11..19',
+ few: 'n % 10 = 2..9 and n % 100 != 11..19',
+ many: 'f != 0'
+ },
+ lv: {
+ zero: 'n % 10 = 0 or n % 100 = 11..19 or v = 2 and f % 100 = 11..19',
+ one: 'n % 10 = 1 and n % 100 != 11 or v = 2 and f % 10 = 1 and f % 100 != 11 or v != 2 and f % 10 = 1'
+ },
+ mg: {
+ one: 'n = 0..1'
+ },
+ mk: {
+ one: 'v = 0 and i % 10 = 1 or f % 10 = 1'
+ },
+ mo: {
+ one: 'i = 1 and v = 0',
+ few: 'v != 0 or n = 0 or n != 1 and n % 100 = 1..19'
+ },
+ mr: {
+ one: 'i = 0 or n = 1'
+ },
+ mt: {
+ one: 'n = 1',
+ few: 'n = 0 or n % 100 = 2..10',
+ many: 'n % 100 = 11..19'
+ },
+ naq: {
+ one: 'n = 1',
+ two: 'n = 2'
+ },
+ nso: {
+ one: 'n = 0..1'
+ },
+ pa: {
+ one: 'n = 0..1'
+ },
+ pl: {
+ one: 'i = 1 and v = 0',
+ few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14',
+ many: 'v = 0 and i != 1 and i % 10 = 0..1 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 12..14'
+ },
+ pt: {
+ one: 'i = 1 and v = 0 or i = 0 and t = 1'
+ },
+ // jscs:disable requireCamelCaseOrUpperCaseIdentifiers
+ pt_PT: {
+ one: 'n = 1 and v = 0'
+ },
+ // jscs:enable requireCamelCaseOrUpperCaseIdentifiers
+ ro: {
+ one: 'i = 1 and v = 0',
+ few: 'v != 0 or n = 0 or n != 1 and n % 100 = 1..19'
+ },
+ ru: {
+ one: 'v = 0 and i % 10 = 1 and i % 100 != 11',
+ many: 'v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14'
+ },
+ se: {
+ one: 'n = 1',
+ two: 'n = 2'
+ },
+ sh: {
+ one: 'v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11',
+ few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14'
+ },
+ shi: {
+ one: 'i = 0 or n = 1',
+ few: 'n = 2..10'
+ },
+ si: {
+ one: 'n = 0,1 or i = 0 and f = 1'
+ },
+ sk: {
+ one: 'i = 1 and v = 0',
+ few: 'i = 2..4 and v = 0',
+ many: 'v != 0'
+ },
+ sl: {
+ one: 'v = 0 and i % 100 = 1',
+ two: 'v = 0 and i % 100 = 2',
+ few: 'v = 0 and i % 100 = 3..4 or v != 0'
+ },
+ sma: {
+ one: 'n = 1',
+ two: 'n = 2'
+ },
+ smi: {
+ one: 'n = 1',
+ two: 'n = 2'
+ },
+ smj: {
+ one: 'n = 1',
+ two: 'n = 2'
+ },
+ smn: {
+ one: 'n = 1',
+ two: 'n = 2'
+ },
+ sms: {
+ one: 'n = 1',
+ two: 'n = 2'
+ },
+ sr: {
+ one: 'v = 0 and i % 10 = 1 and i % 100 != 11 or f % 10 = 1 and f % 100 != 11',
+ few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14 or f % 10 = 2..4 and f % 100 != 12..14'
+ },
+ ti: {
+ one: 'n = 0..1'
+ },
+ tl: {
+ one: 'i = 0..1 and v = 0'
+ },
+ tzm: {
+ one: 'n = 0..1 or n = 11..99'
+ },
+ uk: {
+ one: 'v = 0 and i % 10 = 1 and i % 100 != 11',
+ few: 'v = 0 and i % 10 = 2..4 and i % 100 != 12..14',
+ many: 'v = 0 and i % 10 = 0 or v = 0 and i % 10 = 5..9 or v = 0 and i % 100 = 11..14'
+ },
+ wa: {
+ one: 'n = 0..1'
+ },
+ zu: {
+ one: 'i = 0 or n = 1'
+ }
+ },
+
+ /**
+ * Plural form transformations, needed for some languages.
+ *
+ * @param count
+ * integer Non-localized quantifier
+ * @param forms
+ * array List of plural forms
+ * @return string Correct form for quantifier in this language
+ */
+ convertPlural: function ( count, forms ) {
+ var pluralRules,
+ pluralFormIndex,
+ index,
+ explicitPluralPattern = new RegExp( '\\d+=', 'i' ),
+ formCount,
+ form;
+
+ if ( !forms || forms.length === 0 ) {
+ return '';
+ }
+
+ // Handle for Explicit 0= & 1= values
+ for ( index = 0; index < forms.length; index++ ) {
+ form = forms[index];
+ if ( explicitPluralPattern.test( form ) ) {
+ formCount = parseInt( form.substring( 0, form.indexOf( '=' ) ), 10 );
+ if ( formCount === count ) {
+ return ( form.substr( form.indexOf( '=' ) + 1 ) );
+ }
+ forms[index] = undefined;
+ }
+ }
+
+ forms = $.map( forms, function ( form ) {
+ if ( form !== undefined ) {
+ return form;
+ }
+ } );
+
+ pluralRules = this.pluralRules[$.i18n().locale];
+
+ if ( !pluralRules ) {
+ // default fallback.
+ return ( count === 1 ) ? forms[0] : forms[1];
+ }
+
+ pluralFormIndex = this.getPluralForm( count, pluralRules );
+ pluralFormIndex = Math.min( pluralFormIndex, forms.length - 1 );
+
+ return forms[pluralFormIndex];
+ },
+
+ /**
+ * For the number, get the plural for index
+ *
+ * @param number
+ * @param pluralRules
+ * @return plural form index
+ */
+ getPluralForm: function ( number, pluralRules ) {
+ var i,
+ pluralForms = [ 'zero', 'one', 'two', 'few', 'many', 'other' ],
+ pluralFormIndex = 0;
+
+ for ( i = 0; i < pluralForms.length; i++ ) {
+ if ( pluralRules[pluralForms[i]] ) {
+ if ( pluralRuleParser( pluralRules[pluralForms[i]], number ) ) {
+ return pluralFormIndex;
+ }
+
+ pluralFormIndex++;
+ }
+ }
+
+ return pluralFormIndex;
+ },
+
+ /**
+ * Converts a number using digitTransformTable.
+ *
+ * @param {number} num Value to be converted
+ * @param {boolean} integer Convert the return value to an integer
+ */
+ convertNumber: function ( num, integer ) {
+ var tmp, item, i,
+ transformTable, numberString, convertedNumber;
+
+ // Set the target Transform table:
+ transformTable = this.digitTransformTable( $.i18n().locale );
+ numberString = String( num );
+ convertedNumber = '';
+
+ if ( !transformTable ) {
+ return num;
+ }
+
+ // Check if the restore to Latin number flag is set:
+ if ( integer ) {
+ if ( parseFloat( num, 10 ) === num ) {
+ return num;
+ }
+
+ tmp = [];
+
+ for ( item in transformTable ) {
+ tmp[transformTable[item]] = item;
+ }
+
+ transformTable = tmp;
+ }
+
+ for ( i = 0; i < numberString.length; i++ ) {
+ if ( transformTable[numberString[i]] ) {
+ convertedNumber += transformTable[numberString[i]];
+ } else {
+ convertedNumber += numberString[i];
+ }
+ }
+
+ return integer ? parseFloat( convertedNumber, 10 ) : convertedNumber;
+ },
+
+ /**
+ * Grammatical transformations, needed for inflected languages.
+ * Invoked by putting {{grammar:form|word}} in a message.
+ * Override this method for languages that need special grammar rules
+ * applied dynamically.
+ *
+ * @param word {String}
+ * @param form {String}
+ * @return {String}
+ */
+ convertGrammar: function ( word, form ) { /*jshint unused: false */
+ return word;
+ },
+
+ /**
+ * Provides an alternative text depending on specified gender. Usage
+ * {{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.
+ *
+ * @param gender
+ * string male, female, or anything else for neutral.
+ * @param forms
+ * array List of gender forms
+ *
+ * @return string
+ */
+ gender: function ( gender, forms ) {
+ if ( !forms || forms.length === 0 ) {
+ return '';
+ }
+
+ while ( forms.length < 2 ) {
+ forms.push( forms[forms.length - 1] );
+ }
+
+ if ( gender === 'male' ) {
+ return forms[0];
+ }
+
+ if ( gender === 'female' ) {
+ return forms[1];
+ }
+
+ return ( forms.length === 3 ) ? forms[2] : forms[0];
+ },
+
+ /**
+ * Get the digit transform table for the given language
+ * See http://cldr.unicode.org/translation/numbering-systems
+ * @param language
+ * @returns {Array|boolean} List of digits in the passed language or false
+ * representation, or boolean false if there is no information.
+ */
+ digitTransformTable: function ( language ) {
+ var tables = {
+ ar: '٠١٢٣٤٥٦٧٨٩',
+ fa: '۰۱۲۳۴۵۶۷۸۹',
+ ml: '൦൧൨൩൪൫൬൭൮൯',
+ kn: '೦೧೨೩೪೫೬೭೮೯',
+ lo: '໐໑໒໓໔໕໖໗໘໙',
+ or: '୦୧୨୩୪୫୬୭୮୯',
+ kh: '០១២៣៤៥៦៧៨៩',
+ pa: '੦੧੨੩੪੫੬੭੮੯',
+ gu: '૦૧૨૩૪૫૬૭૮૯',
+ hi: '०१२३४५६७८९',
+ my: '၀၁၂၃၄၅၆၇၈၉',
+ ta: '௦௧௨௩௪௫௬௭௮௯',
+ te: '౦౧౨౩౪౫౬౭౮౯',
+ th: '๐๑๒๓๔๕๖๗๘๙', // FIXME use iso 639 codes
+ bo: '༠༡༢༣༤༥༦༧༨༩' // FIXME use iso 639 codes
+ };
+
+ if ( !tables[language] ) {
+ return false;
+ }
+
+ return tables[language].split( '' );
+ }
+ };
+
+ $.extend( $.i18n.languages, {
+ 'default': language
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/jquery.i18n.messagestore.js b/resources/lib/jquery.i18n/src/jquery.i18n.messagestore.js
new file mode 100644
index 00000000..759295ce
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/jquery.i18n.messagestore.js
@@ -0,0 +1,125 @@
+/**
+ * jQuery Internationalization library - Message Store
+ *
+ * Copyright (C) 2012 Santhosh Thottingal
+ *
+ * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do anything special to
+ * choose one license or the other and you don't have to notify anyone which license you are using.
+ * You are free to use UniversalLanguageSelector in commercial projects as long as the copyright
+ * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
+ *
+ * @licence GNU General Public Licence 2.0 or later
+ * @licence MIT License
+ */
+
+( function ( $, window, undefined ) {
+ 'use strict';
+
+ var MessageStore = function () {
+ this.messages = {};
+ this.sources = {};
+ };
+
+ /**
+ * See https://github.com/wikimedia/jquery.i18n/wiki/Specification#wiki-Message_File_Loading
+ */
+ MessageStore.prototype = {
+
+ /**
+ * General message loading API This can take a URL string for
+ * the json formatted messages.
+ * <code>load('path/to/all_localizations.json');</code>
+ *
+ * This can also load a localization file for a locale <code>
+ * load( 'path/to/de-messages.json', 'de' );
+ * </code>
+ * A data object containing message key- message translation mappings
+ * can also be passed Eg:
+ * <code>
+ * load( { 'hello' : 'Hello' }, optionalLocale );
+ * </code> If the data argument is
+ * null/undefined/false,
+ * all cached messages for the i18n instance will get reset.
+ *
+ * @param {String|Object} source
+ * @param {String} locale Language tag
+ * @return {jQuery.Promise}
+ */
+ load: function ( source, locale ) {
+ var key = null,
+ deferred = null,
+ deferreds = [],
+ messageStore = this;
+
+ if ( typeof source === 'string' ) {
+ // This is a URL to the messages file.
+ $.i18n.log( 'Loading messages from: ' + source );
+ deferred = jsonMessageLoader( source )
+ .done( function ( localization ) {
+ messageStore.set( locale, localization );
+ } );
+
+ return deferred.promise();
+ }
+
+ if ( locale ) {
+ // source is an key-value pair of messages for given locale
+ messageStore.set( locale, source );
+
+ return $.Deferred().resolve();
+ } else {
+ // source is a key-value pair of locales and their source
+ for ( key in source ) {
+ if ( Object.prototype.hasOwnProperty.call( source, key ) ) {
+ locale = key;
+ // No {locale} given, assume data is a group of languages,
+ // call this function again for each language.
+ deferreds.push( messageStore.load( source[key], locale ) );
+ }
+ }
+ return $.when.apply( $, deferreds );
+ }
+
+ },
+
+ /**
+ * Set messages to the given locale.
+ * If locale exists, add messages to the locale.
+ * @param locale
+ * @param messages
+ */
+ set: function ( locale, messages ) {
+ if ( !this.messages[locale] ) {
+ this.messages[locale] = messages;
+ } else {
+ this.messages[locale] = $.extend( this.messages[locale], messages );
+ }
+ },
+
+ /**
+ *
+ * @param locale
+ * @param messageKey
+ * @returns {Boolean}
+ */
+ get: function ( locale, messageKey ) {
+ return this.messages[locale] && this.messages[locale][messageKey];
+ }
+ };
+
+ function jsonMessageLoader( url ) {
+ var deferred = $.Deferred();
+
+ $.getJSON( url )
+ .done( deferred.resolve )
+ .fail( function ( jqxhr, settings, exception ) {
+ $.i18n.log( 'Error in loading messages from ' + url + ' Exception: ' + exception );
+ // Ignore 404 exception, because we are handling fallabacks explicitly
+ deferred.resolve();
+ } );
+
+ return deferred.promise();
+ }
+
+ $.extend( $.i18n.messageStore, new MessageStore() );
+}( jQuery, window ) );
diff --git a/resources/lib/jquery.i18n/src/jquery.i18n.parser.js b/resources/lib/jquery.i18n/src/jquery.i18n.parser.js
new file mode 100644
index 00000000..3dea2842
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/jquery.i18n.parser.js
@@ -0,0 +1,309 @@
+/**
+ * jQuery Internationalization library
+ *
+ * Copyright (C) 2011-2013 Santhosh Thottingal, Neil Kandalgaonkar
+ *
+ * jquery.i18n is dual licensed GPLv2 or later and MIT. You don't have to do
+ * anything special to choose one license or the other and you don't have to
+ * notify anyone which license you are using. You are free to use
+ * UniversalLanguageSelector in commercial projects as long as the copyright
+ * header is left intact. See files GPL-LICENSE and MIT-LICENSE for details.
+ *
+ * @licence GNU General Public Licence 2.0 or later
+ * @licence MIT License
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ var MessageParser = function ( options ) {
+ this.options = $.extend( {}, $.i18n.parser.defaults, options );
+ this.language = $.i18n.languages[String.locale] || $.i18n.languages['default'];
+ this.emitter = $.i18n.parser.emitter;
+ };
+
+ MessageParser.prototype = {
+
+ constructor: MessageParser,
+
+ simpleParse: function ( message, parameters ) {
+ return message.replace( /\$(\d+)/g, function ( str, match ) {
+ var index = parseInt( match, 10 ) - 1;
+
+ return parameters[index] !== undefined ? parameters[index] : '$' + match;
+ } );
+ },
+
+ parse: function ( message, replacements ) {
+ if ( message.indexOf( '{{' ) < 0 ) {
+ return this.simpleParse( message, replacements );
+ }
+
+ this.emitter.language = $.i18n.languages[$.i18n().locale] ||
+ $.i18n.languages['default'];
+
+ return this.emitter.emit( this.ast( message ), replacements );
+ },
+
+ ast: function ( message ) {
+ var pipe, colon, backslash, anyCharacter, dollar, digits, regularLiteral,
+ regularLiteralWithoutBar, regularLiteralWithoutSpace, escapedOrLiteralWithoutBar,
+ escapedOrRegularLiteral, templateContents, templateName, openTemplate,
+ closeTemplate, expression, paramExpression, result,
+ pos = 0;
+
+ // Try parsers until one works, if none work return null
+ function choice( parserSyntax ) {
+ return function () {
+ var i, result;
+
+ for ( i = 0; i < parserSyntax.length; i++ ) {
+ result = parserSyntax[i]();
+
+ if ( result !== null ) {
+ return result;
+ }
+ }
+
+ return null;
+ };
+ }
+
+ // Try several parserSyntax-es in a row.
+ // All must succeed; otherwise, return null.
+ // This is the only eager one.
+ function sequence( parserSyntax ) {
+ var i, res,
+ originalPos = pos,
+ result = [];
+
+ for ( i = 0; i < parserSyntax.length; i++ ) {
+ res = parserSyntax[i]();
+
+ if ( res === null ) {
+ pos = originalPos;
+
+ return null;
+ }
+
+ result.push( res );
+ }
+
+ 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,
+ 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
+
+ function makeStringParser( s ) {
+ var len = s.length;
+
+ return function () {
+ var result = null;
+
+ if ( message.substr( pos, len ) === s ) {
+ result = s;
+ pos += len;
+ }
+
+ return result;
+ };
+ }
+
+ function makeRegexParser( regex ) {
+ return function () {
+ var matches = message.substr( pos ).match( regex );
+
+ if ( matches === null ) {
+ return null;
+ }
+
+ pos += matches[0].length;
+
+ return matches[0];
+ };
+ }
+
+ pipe = makeStringParser( '|' );
+ colon = makeStringParser( ':' );
+ backslash = makeStringParser( '\\' );
+ anyCharacter = makeRegexParser( /^./ );
+ dollar = makeStringParser( '$' );
+ digits = makeRegexParser( /^\d+/ );
+ regularLiteral = makeRegexParser( /^[^{}\[\]$\\]/ );
+ regularLiteralWithoutBar = makeRegexParser( /^[^{}\[\]$\\|]/ );
+ regularLiteralWithoutSpace = makeRegexParser( /^[^{}\[\]$\s]/ );
+
+ // There is a general pattern:
+ // parse a thing;
+ // if it worked, apply transform,
+ // otherwise return null.
+ // But using this as a combinator seems to cause problems
+ // when combined with nOrMore().
+ // May be some scoping issue.
+ function transform( p, fn ) {
+ return function () {
+ var result = p();
+
+ return result === null ? null : fn( result );
+ };
+ }
+
+ // Used to define "literals" within template parameters. The pipe
+ // character is the parameter delimeter, so by default
+ // it is not a literal in the parameter
+ function literalWithoutBar() {
+ var result = nOrMore( 1, escapedOrLiteralWithoutBar )();
+
+ return result === null ? null : result.join( '' );
+ }
+
+ function literal() {
+ var result = nOrMore( 1, escapedOrRegularLiteral )();
+
+ return result === null ? null : result.join( '' );
+ }
+
+ function escapedLiteral() {
+ var result = sequence( [ backslash, anyCharacter ] );
+
+ return result === null ? null : result[1];
+ }
+
+ choice( [ escapedLiteral, regularLiteralWithoutSpace ] );
+ escapedOrLiteralWithoutBar = choice( [ escapedLiteral, regularLiteralWithoutBar ] );
+ escapedOrRegularLiteral = choice( [ escapedLiteral, regularLiteral ] );
+
+ function replacement() {
+ var result = sequence( [ dollar, digits ] );
+
+ if ( result === null ) {
+ return null;
+ }
+
+ return [ 'REPLACE', parseInt( result[1], 10 ) - 1 ];
+ }
+
+ templateName = transform(
+ // see $wgLegalTitleChars
+ // not allowing : due to the need to catch "PLURAL:$1"
+ makeRegexParser( /^[ !"$&'()*,.\/0-9;=?@A-Z\^_`a-z~\x80-\xFF+\-]+/ ),
+
+ function ( result ) {
+ return result.toString();
+ }
+ );
+
+ function templateParam() {
+ var expr,
+ result = sequence( [ pipe, nOrMore( 0, paramExpression ) ] );
+
+ if ( result === null ) {
+ return null;
+ }
+
+ expr = result[1];
+
+ // use a "CONCAT" operator if there are multiple nodes,
+ // otherwise return the first node, raw.
+ return expr.length > 1 ? [ 'CONCAT' ].concat( expr ) : expr[0];
+ }
+
+ function templateWithReplacement() {
+ var result = sequence( [ templateName, colon, replacement ] );
+
+ return result === null ? null : [ result[0], result[2] ];
+ }
+
+ function templateWithOutReplacement() {
+ var result = sequence( [ templateName, colon, paramExpression ] );
+
+ return result === null ? null : [ result[0], result[2] ];
+ }
+
+ templateContents = choice( [
+ function () {
+ var res = sequence( [
+ // templates can have placeholders for dynamic
+ // replacement eg: {{PLURAL:$1|one car|$1 cars}}
+ // or no placeholders eg:
+ // {{GRAMMAR:genitive|{{SITENAME}}}
+ choice( [ templateWithReplacement, templateWithOutReplacement ] ),
+ nOrMore( 0, templateParam )
+ ] );
+
+ return res === null ? null : res[0].concat( res[1] );
+ },
+ function () {
+ var res = sequence( [ templateName, nOrMore( 0, templateParam ) ] );
+
+ if ( res === null ) {
+ return null;
+ }
+
+ return [ res[0] ].concat( res[1] );
+ }
+ ] );
+
+ openTemplate = makeStringParser( '{{' );
+ closeTemplate = makeStringParser( '}}' );
+
+ function template() {
+ var result = sequence( [ openTemplate, templateContents, closeTemplate ] );
+
+ return result === null ? null : result[1];
+ }
+
+ expression = choice( [ template, replacement, literal ] );
+ paramExpression = choice( [ template, replacement, literalWithoutBar ] );
+
+ function start() {
+ var result = nOrMore( 0, expression )();
+
+ if ( result === null ) {
+ return null;
+ }
+
+ return [ 'CONCAT' ].concat( result );
+ }
+
+ result = start();
+
+ /*
+ * For success, the pos must have gotten to the end of the input
+ * and returned a non-null.
+ * n.b. This is part of language infrastructure, so we do not throw an internationalizable message.
+ */
+ if ( result === null || pos !== message.length ) {
+ throw new Error( 'Parse error at position ' + pos.toString() + ' in input: ' + message );
+ }
+
+ return result;
+ }
+
+ };
+
+ $.extend( $.i18n.parser, new MessageParser() );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/bs.js b/resources/lib/jquery.i18n/src/languages/bs.js
new file mode 100644
index 00000000..5370069e
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/bs.js
@@ -0,0 +1,22 @@
+/**
+ * Bosnian (bosanski) language functions
+ */
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.bs = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ switch ( form ) {
+ case 'instrumental': // instrumental
+ word = 's ' + word;
+ break;
+ case 'lokativ': // locative
+ word = 'o ' + word;
+ break;
+ }
+
+ return word;
+ }
+ } );
+
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/dsb.js b/resources/lib/jquery.i18n/src/languages/dsb.js
new file mode 100644
index 00000000..cc069ebf
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/dsb.js
@@ -0,0 +1,22 @@
+/**
+ * Lower Sorbian (Dolnoserbski) language functions
+ */
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.dsb = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ switch ( form ) {
+ case 'instrumental': // instrumental
+ word = 'z ' + word;
+ break;
+ case 'lokatiw': // lokatiw
+ word = 'wo ' + word;
+ break;
+ }
+
+ return word;
+ }
+ } );
+
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/fi.js b/resources/lib/jquery.i18n/src/languages/fi.js
new file mode 100644
index 00000000..d8e9578a
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/fi.js
@@ -0,0 +1,49 @@
+/**
+ * Finnish (Suomi) language functions
+ *
+ * @author Santhosh Thottingal
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.fi = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ // vowel harmony flag
+ var aou = word.match( /[aou][^äöy]*$/i ),
+ origWord = word;
+ if ( word.match( /wiki$/i ) ) {
+ aou = false;
+ }
+
+ // append i after final consonant
+ if ( word.match( /[bcdfghjklmnpqrstvwxz]$/i ) ) {
+ word += 'i';
+ }
+
+ switch ( form ) {
+ case 'genitive':
+ word += 'n';
+ break;
+ case 'elative':
+ word += ( aou ? 'sta' : 'stä' );
+ break;
+ case 'partitive':
+ word += ( aou ? 'a' : 'ä' );
+ break;
+ case 'illative':
+ // Double the last letter and add 'n'
+ word += word.substr( word.length - 1 ) + 'n';
+ break;
+ case 'inessive':
+ word += ( aou ? 'ssa' : 'ssä' );
+ break;
+ default:
+ word = origWord;
+ break;
+ }
+
+ return word;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/ga.js b/resources/lib/jquery.i18n/src/languages/ga.js
new file mode 100644
index 00000000..1aceab75
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/ga.js
@@ -0,0 +1,38 @@
+/**
+ * Irish (Gaeilge) language functions
+ */
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.ga = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ if ( form === 'ainmlae' ) {
+ switch ( word ) {
+ case 'an Domhnach':
+ word = 'Dé Domhnaigh';
+ break;
+ case 'an Luan':
+ word = 'Dé Luain';
+ break;
+ case 'an Mháirt':
+ word = 'Dé Mháirt';
+ break;
+ case 'an Chéadaoin':
+ word = 'Dé Chéadaoin';
+ break;
+ case 'an Déardaoin':
+ word = 'Déardaoin';
+ break;
+ case 'an Aoine':
+ word = 'Dé hAoine';
+ break;
+ case 'an Satharn':
+ word = 'Dé Sathairn';
+ break;
+ }
+ }
+
+ return word;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/he.js b/resources/lib/jquery.i18n/src/languages/he.js
new file mode 100644
index 00000000..cbbe90b9
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/he.js
@@ -0,0 +1,31 @@
+/**
+ * Hebrew (עברית) language functions
+ */
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.he = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ switch ( form ) {
+ case 'prefixed':
+ case 'תחילית': // the same word in Hebrew
+ // Duplicate prefixed "Waw", but only if it's not already double
+ if ( word.substr( 0, 1 ) === 'ו' && word.substr( 0, 2 ) !== 'וו' ) {
+ word = 'ו' + word;
+ }
+
+ // Remove the "He" if prefixed
+ if ( word.substr( 0, 1 ) === 'ה' ) {
+ word = word.substr( 1, word.length );
+ }
+
+ // Add a hyphen (maqaf) before numbers and non-Hebrew letters
+ if ( word.substr( 0, 1 ) < 'א' || word.substr( 0, 1 ) > 'ת' ) {
+ word = '־' + word;
+ }
+ }
+
+ return word;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/hsb.js b/resources/lib/jquery.i18n/src/languages/hsb.js
new file mode 100644
index 00000000..957616f6
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/hsb.js
@@ -0,0 +1,21 @@
+/**
+ * Upper Sorbian (Hornjoserbsce) language functions
+ */
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.hsb = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ switch ( form ) {
+ case 'instrumental': // instrumental
+ word = 'z ' + word;
+ break;
+ case 'lokatiw': // lokatiw
+ word = 'wo ' + word;
+ break;
+ }
+
+ return word;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/hu.js b/resources/lib/jquery.i18n/src/languages/hu.js
new file mode 100644
index 00000000..1177b850
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/hu.js
@@ -0,0 +1,26 @@
+/**
+ * Hungarian language functions
+ *
+ * @author Santhosh Thottingal
+ */
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.hu = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ switch ( form ) {
+ case 'rol':
+ word += 'ról';
+ break;
+ case 'ba':
+ word += 'ba';
+ break;
+ case 'k':
+ word += 'k';
+ break;
+ }
+
+ return word;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/hy.js b/resources/lib/jquery.i18n/src/languages/hy.js
new file mode 100644
index 00000000..9c568992
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/hy.js
@@ -0,0 +1,25 @@
+/**
+ * Armenian (Հայերեն) language functions
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.hy = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ if ( form === 'genitive' ) { // սեռական հոլով
+ if ( word.substr( -1 ) === 'ա' ) {
+ word = word.substr( 0, word.length - 1 ) + 'այի';
+ } else if ( word.substr( -1 ) === 'ո' ) {
+ word = word.substr( 0, word.length - 1 ) + 'ոյի';
+ } else if ( word.substr( -4 ) === 'գիրք' ) {
+ word = word.substr( 0, word.length - 4 ) + 'գրքի';
+ } else {
+ word = word + 'ի';
+ }
+ }
+
+ return word;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/la.js b/resources/lib/jquery.i18n/src/languages/la.js
new file mode 100644
index 00000000..11c1122d
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/la.js
@@ -0,0 +1,54 @@
+/**
+ * Latin (lingua Latina) language functions
+ *
+ * @author Santhosh Thottingal
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.la = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ switch ( form ) {
+ case 'genitive':
+ // only a few declensions, and even for those mostly the singular only
+ word = word.replace( /u[ms]$/i, 'i' ); // 2nd declension singular
+ word = word.replace( /ommunia$/i, 'ommunium' ); // 3rd declension neuter plural (partly)
+ word = word.replace( /a$/i, 'ae' ); // 1st declension singular
+ word = word.replace( /libri$/i, 'librorum' ); // 2nd declension plural (partly)
+ word = word.replace( /nuntii$/i, 'nuntiorum' ); // 2nd declension plural (partly)
+ word = word.replace( /tio$/i, 'tionis' ); // 3rd declension singular (partly)
+ word = word.replace( /ns$/i, 'ntis' );
+ word = word.replace( /as$/i, 'atis' );
+ word = word.replace( /es$/i, 'ei' ); // 5th declension singular
+ break;
+ case 'accusative':
+ // only a few declensions, and even for those mostly the singular only
+ word = word.replace( /u[ms]$/i, 'um' ); // 2nd declension singular
+ word = word.replace( /ommunia$/i, 'am' ); // 3rd declension neuter plural (partly)
+ word = word.replace( /a$/i, 'ommunia' ); // 1st declension singular
+ word = word.replace( /libri$/i, 'libros' ); // 2nd declension plural (partly)
+ word = word.replace( /nuntii$/i, 'nuntios' );// 2nd declension plural (partly)
+ word = word.replace( /tio$/i, 'tionem' ); // 3rd declension singular (partly)
+ word = word.replace( /ns$/i, 'ntem' );
+ word = word.replace( /as$/i, 'atem' );
+ word = word.replace( /es$/i, 'em' ); // 5th declension singular
+ break;
+ case 'ablative':
+ // only a few declensions, and even for those mostly the singular only
+ word = word.replace( /u[ms]$/i, 'o' ); // 2nd declension singular
+ word = word.replace( /ommunia$/i, 'ommunibus' ); // 3rd declension neuter plural (partly)
+ word = word.replace( /a$/i, 'a' ); // 1st declension singular
+ word = word.replace( /libri$/i, 'libris' ); // 2nd declension plural (partly)
+ word = word.replace( /nuntii$/i, 'nuntiis' ); // 2nd declension plural (partly)
+ word = word.replace( /tio$/i, 'tione' ); // 3rd declension singular (partly)
+ word = word.replace( /ns$/i, 'nte' );
+ word = word.replace( /as$/i, 'ate' );
+ word = word.replace( /es$/i, 'e' ); // 5th declension singular
+ break;
+ }
+
+ return word;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/ml.js b/resources/lib/jquery.i18n/src/languages/ml.js
new file mode 100644
index 00000000..f724b7b2
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/ml.js
@@ -0,0 +1,98 @@
+/**
+ * Malayalam language functions
+ *
+ * @author Santhosh Thottingal
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.ml = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ form = form.toLowerCase();
+ switch ( form ) {
+ case 'ഉദ്ദേശിക':
+ case 'dative':
+ if ( word.substr( -1 ) === 'ു' ||
+ word.substr( -1 ) === 'ൂ' ||
+ word.substr( -1 ) === 'ൗ' ||
+ word.substr( -1 ) === 'ൌ'
+ ) {
+ word += 'വിന്';
+ } else if ( word.substr( -1 ) === 'ം' ) {
+ word = word.substr( 0, word.length - 1 ) + 'ത്തിന്';
+ } else if ( word.substr( -1 ) === 'ൻ' ) {
+ // Atomic chillu n. അവൻ -> അവന്
+ word = word.substr( 0, word.length - 1 ) + 'ന്';
+ } else if ( word.substr( -3 ) === 'ന്\u200d' ) {
+ // chillu n. അവൻ -> അവന്
+ word = word.substr( 0, word.length - 1 );
+ } else if ( word.substr( -1 ) === 'ൾ' || word.substr( -3 ) === 'ള്\u200d' ) {
+ word += 'ക്ക്';
+ } else if ( word.substr( -1 ) === 'ർ' || word.substr( -3 ) === 'ര്\u200d' ) {
+ word += 'ക്ക്';
+ } else if ( word.substr( -1 ) === 'ൽ' ) {
+ // Atomic chillu ൽ , ഫയൽ -> ഫയലിന്
+ word = word.substr( 0, word.length - 1 ) + 'ലിന്';
+ } else if ( word.substr( -3 ) === 'ല്\u200d' ) {
+ // chillu ല്\u200d , ഫയല്\u200d -> ഫയലിന്
+ word = word.substr( 0, word.length - 2 ) + 'ിന്';
+ } else if ( word.substr( -2 ) === 'ു്' ) {
+ word = word.substr( 0, word.length - 2 ) + 'ിന്';
+ } else if ( word.substr( -1 ) === '്' ) {
+ word = word.substr( 0, word.length - 1 ) + 'ിന്';
+ } else {
+ // കാവ്യ -> കാവ്യയ്ക്ക്, ഹരി -> ഹരിയ്ക്ക്, മല -> മലയ്ക്ക്
+ word += 'യ്ക്ക്';
+ }
+
+ break;
+ case 'സംബന്ധിക':
+ case 'genitive':
+ if ( word.substr( -1 ) === 'ം' ) {
+ word = word.substr( 0, word.length - 1 ) + 'ത്തിന്റെ';
+ } else if ( word.substr( -2 ) === 'ു്' ) {
+ word = word.substr( 0, word.length - 2 ) + 'ിന്റെ';
+ } else if ( word.substr( -1 ) === '്' ) {
+ word = word.substr( 0, word.length - 1 ) + 'ിന്റെ';
+ } else if ( word.substr( -1 ) === 'ു' ||
+ word.substr( -1 ) === 'ൂ' ||
+ word.substr( -1 ) === 'ൗ' ||
+ word.substr( -1 ) === 'ൌ'
+ ) {
+ word += 'വിന്റെ';
+ } else if ( word.substr( -1 ) === 'ൻ' ) {
+ // Atomic chillu n. അവൻ -> അവന്റെ
+ word = word.substr( 0, word.length - 1 ) + 'ന്റെ';
+ } else if ( word.substr( -3 ) === 'ന്\u200d' ) {
+ // chillu n. അവൻ -> അവന്റെ
+ word = word.substr( 0, word.length - 1 ) + 'റെ';
+ } else if ( word.substr( -3 ) === 'ള്\u200d' ) {
+ // chillu n. അവൾ -> അവളുടെ
+ word = word.substr( 0, word.length - 2 ) + 'ുടെ';
+ } else if ( word.substr( -1 ) === 'ൾ' ) {
+ // Atomic chillu n. അവള്\u200d -> അവളുടെ
+ word = word.substr( 0, word.length - 1 ) + 'ളുടെ';
+ } else if ( word.substr( -1 ) === 'ൽ' ) {
+ // Atomic l. മുയല്\u200d -> മുയലിന്റെ
+ word = word.substr( 0, word.length - 1 ) + 'ലിന്റെ';
+ } else if ( word.substr( -3 ) === 'ല്\u200d' ) {
+ // chillu l. മുയല്\u200d -> അവളുടെ
+ word = word.substr( 0, word.length - 2 ) + 'ിന്റെ';
+ } else if ( word.substr( -3 ) === 'ര്\u200d' ) {
+ // chillu r. അവര്\u200d -> അവരുടെ
+ word = word.substr( 0, word.length - 2 ) + 'ുടെ';
+ } else if ( word.substr( -1 ) === 'ർ' ) {
+ // Atomic chillu r. അവർ -> അവരുടെ
+ word = word.substr( 0, word.length - 1 ) + 'രുടെ';
+ } else {
+ word += 'യുടെ';
+ }
+
+ break;
+ }
+
+ return word;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/os.js b/resources/lib/jquery.i18n/src/languages/os.js
new file mode 100644
index 00000000..47443671
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/os.js
@@ -0,0 +1,76 @@
+/**
+ * Ossetian (Ирон) language functions
+ *
+ * @author Santhosh Thottingal
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.os = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ var endAllative, jot, hyphen, ending;
+
+ // Ending for allative case
+ endAllative = 'мæ';
+ // Variable for 'j' beetwen vowels
+ jot = '';
+ // Variable for "-" for not Ossetic words
+ hyphen = '';
+ // Variable for ending
+ ending = '';
+
+ if ( word.match( /тæ$/i ) ) {
+ // Checking if the $word is in plural form
+ word = word.substring( 0, word.length - 1 );
+ endAllative = 'æм';
+ } else if ( word.match( /[аæеёиоыэюя]$/i ) ) {
+ // Works if word is in singular form.
+ // Checking if word ends on one of the vowels: е, ё, и, о, ы, э, ю,
+ // я.
+ jot = 'й';
+ } 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.substring( word.length - 2, word.length - 1 )
+ .match( /[аæеёиоыэюя]$/i ) ) {
+ jot = 'й';
+ }
+ } else if ( !word.match( /[бвгджзйклмнопрстфхцчшщьъ]$/i ) ) {
+ hyphen = '-';
+ }
+
+ switch ( form ) {
+ case 'genitive':
+ ending = hyphen + jot + 'ы';
+ break;
+ case 'dative':
+ ending = hyphen + jot + 'æн';
+ break;
+ case 'allative':
+ ending = hyphen + endAllative;
+ break;
+ case 'ablative':
+ if ( jot === 'й' ) {
+ ending = hyphen + jot + 'æ';
+ } else {
+ ending = hyphen + jot + 'æй';
+ }
+ break;
+ case 'superessive':
+ ending = hyphen + jot + 'ыл';
+ break;
+ case 'equative':
+ ending = hyphen + jot + 'ау';
+ break;
+ case 'comitative':
+ ending = hyphen + 'имæ';
+ break;
+ }
+
+ return word + ending;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/ru.js b/resources/lib/jquery.i18n/src/languages/ru.js
new file mode 100644
index 00000000..893b2386
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/ru.js
@@ -0,0 +1,29 @@
+/**
+ * Russian (Русский) language functions
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.ru = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ if ( form === 'genitive' ) { // родительный падеж
+ if ( word.substr( -1 ) === 'ь' ) {
+ word = word.substr( 0, word.length - 1 ) + 'я';
+ } else if ( word.substr( -2 ) === 'ия' ) {
+ word = word.substr( 0, word.length - 2 ) + 'ии';
+ } else if ( word.substr( -2 ) === 'ка' ) {
+ word = word.substr( 0, word.length - 2 ) + 'ки';
+ } else if ( word.substr( -2 ) === 'ти' ) {
+ word = word.substr( 0, word.length - 2 ) + 'тей';
+ } else if ( word.substr( -2 ) === 'ды' ) {
+ word = word.substr( 0, word.length - 2 ) + 'дов';
+ } else if ( word.substr( -3 ) === 'ник' ) {
+ word = word.substr( 0, word.length - 3 ) + 'ника';
+ }
+ }
+
+ return word;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/sl.js b/resources/lib/jquery.i18n/src/languages/sl.js
new file mode 100644
index 00000000..a3aafc3b
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/sl.js
@@ -0,0 +1,26 @@
+/**
+ * Slovenian (Slovenščina) language functions
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.sl = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ switch ( form ) {
+ // locative
+ case 'mestnik':
+ word = 'o ' + word;
+
+ break;
+ // instrumental
+ case 'orodnik':
+ word = 'z ' + word;
+
+ break;
+ }
+
+ return word;
+ }
+ } );
+}( jQuery ) );
diff --git a/resources/lib/jquery.i18n/src/languages/uk.js b/resources/lib/jquery.i18n/src/languages/uk.js
new file mode 100644
index 00000000..8e69efcd
--- /dev/null
+++ b/resources/lib/jquery.i18n/src/languages/uk.js
@@ -0,0 +1,39 @@
+/**
+ * Ukrainian (Українська) language functions
+ */
+
+( function ( $ ) {
+ 'use strict';
+
+ $.i18n.languages.uk = $.extend( {}, $.i18n.languages['default'], {
+ convertGrammar: function ( word, form ) {
+ switch ( form ) {
+ case 'genitive': // родовий відмінок
+ if ( word.substr( -1 ) === 'ь' ) {
+ word = word.substr( 0, word.length - 1 ) + 'я';
+ } else if ( word.substr( -2 ) === 'ія' ) {
+ word = word.substr( 0, word.length - 2 ) + 'ії';
+ } else if ( word.substr( -2 ) === 'ка' ) {
+ word = word.substr( 0, word.length - 2 ) + 'ки';
+ } else if ( word.substr( -2 ) === 'ти' ) {
+ word = word.substr( 0, word.length - 2 ) + 'тей';
+ } else if ( word.substr( -2 ) === 'ды' ) {
+ word = word.substr( 0, word.length - 2 ) + 'дов';
+ } else if ( word.substr( -3 ) === 'ник' ) {
+ word = word.substr( 0, word.length - 3 ) + 'ника';
+ }
+
+ break;
+ case 'accusative': // знахідний відмінок
+ if ( word.substr( -2 ) === 'ія' ) {
+ word = word.substr( 0, word.length - 2 ) + 'ію';
+ }
+
+ break;
+ }
+
+ return word;
+ }
+ } );
+
+}( jQuery ) );
diff --git a/resources/lib/json2/json2.js b/resources/lib/json2/json2.js
index deb88ec9..58384577 100644
--- a/resources/lib/json2/json2.js
+++ b/resources/lib/json2/json2.js
@@ -1,6 +1,6 @@
/*
json2.js
- 2014-02-04
+ 2015-05-03
Public Domain.
@@ -17,7 +17,9 @@
This file creates a global JSON object containing two methods: stringify
- and parse.
+ and parse. This file is provides the ES5 JSON capability to ES3 systems.
+ If a project might run on IE8 or earlier, then this file should be included.
+ This file does nothing on ES5 systems.
JSON.stringify(value, replacer, space)
value any JavaScript value, usually an object or array.
@@ -48,7 +50,9 @@
Date.prototype.toJSON = function (key) {
function f(n) {
// Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
+ return n < 10
+ ? '0' + n
+ : n;
}
return this.getUTCFullYear() + '-' +
@@ -94,8 +98,9 @@
// text is '[\n\t"e",\n\t{\n\t\t"pluribus": "unum"\n\t}\n]'
text = JSON.stringify([new Date()], function (key, value) {
- return this[key] instanceof Date ?
- 'Date(' + this[key] + ')' : value;
+ return this[key] instanceof Date
+ ? 'Date(' + this[key] + ')'
+ : value;
});
// text is '["Date(---current time---)"]'
@@ -146,10 +151,12 @@
redistribute.
*/
-/*jslint evil: true, regexp: true */
+/*jslint
+ eval, for, this
+*/
-/*members "", "\b", "\t", "\n", "\f", "\r", "\"", JSON, "\\", apply,
- call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
+/*property
+ JSON, apply, call, charCodeAt, getUTCDate, getUTCFullYear, getUTCHours,
getUTCMinutes, getUTCMonth, getUTCSeconds, hasOwnProperty, join,
lastIndex, length, parse, prototype, push, replace, slice, stringify,
test, toJSON, toString, valueOf
@@ -165,10 +172,23 @@ if (typeof JSON !== 'object') {
(function () {
'use strict';
+
+ var rx_one = /^[\],:{}\s]*$/,
+ rx_two = /\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,
+ rx_three = /"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
+ rx_four = /(?:^|:|,)(?:\s*\[)+/g,
+ rx_escapable = /[\\\"\u0000-\u001f\u007f-\u009f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
+ rx_dangerous = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
function f(n) {
// Format integers to have at least two digits.
- return n < 10 ? '0' + n : n;
+ return n < 10
+ ? '0' + n
+ : n;
+ }
+
+ function this_value() {
+ return this.valueOf();
}
if (typeof Date.prototype.toJSON !== 'function') {
@@ -176,25 +196,21 @@ if (typeof JSON !== 'object') {
Date.prototype.toJSON = function () {
return isFinite(this.valueOf())
- ? this.getUTCFullYear() + '-' +
- f(this.getUTCMonth() + 1) + '-' +
- f(this.getUTCDate()) + 'T' +
- f(this.getUTCHours()) + ':' +
- f(this.getUTCMinutes()) + ':' +
- f(this.getUTCSeconds()) + 'Z'
+ ? this.getUTCFullYear() + '-' +
+ f(this.getUTCMonth() + 1) + '-' +
+ f(this.getUTCDate()) + 'T' +
+ f(this.getUTCHours()) + ':' +
+ f(this.getUTCMinutes()) + ':' +
+ f(this.getUTCSeconds()) + 'Z'
: null;
};
- String.prototype.toJSON =
- Number.prototype.toJSON =
- Boolean.prototype.toJSON = function () {
- return this.valueOf();
- };
+ Boolean.prototype.toJSON = this_value;
+ Number.prototype.toJSON = this_value;
+ String.prototype.toJSON = this_value;
}
- var cx,
- escapable,
- gap,
+ var gap,
indent,
meta,
rep;
@@ -207,13 +223,15 @@ if (typeof JSON !== 'object') {
// Otherwise we must also replace the offending characters with safe escape
// sequences.
- escapable.lastIndex = 0;
- return escapable.test(string) ? '"' + string.replace(escapable, function (a) {
- var c = meta[a];
- return typeof c === 'string'
- ? c
- : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
- }) + '"' : '"' + string + '"';
+ rx_escapable.lastIndex = 0;
+ return rx_escapable.test(string)
+ ? '"' + string.replace(rx_escapable, function (a) {
+ var c = meta[a];
+ return typeof c === 'string'
+ ? c
+ : '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ }) + '"'
+ : '"' + string + '"';
}
@@ -253,7 +271,9 @@ if (typeof JSON !== 'object') {
// JSON numbers must be finite. Encode non-finite numbers as null.
- return isFinite(value) ? String(value) : 'null';
+ return isFinite(value)
+ ? String(value)
+ : 'null';
case 'boolean':
case 'null':
@@ -299,8 +319,8 @@ if (typeof JSON !== 'object') {
v = partial.length === 0
? '[]'
: gap
- ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
- : '[' + partial.join(',') + ']';
+ ? '[\n' + gap + partial.join(',\n' + gap) + '\n' + mind + ']'
+ : '[' + partial.join(',') + ']';
gap = mind;
return v;
}
@@ -314,7 +334,11 @@ if (typeof JSON !== 'object') {
k = rep[i];
v = str(k, value);
if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ partial.push(quote(k) + (
+ gap
+ ? ': '
+ : ':'
+ ) + v);
}
}
}
@@ -326,7 +350,11 @@ if (typeof JSON !== 'object') {
if (Object.prototype.hasOwnProperty.call(value, k)) {
v = str(k, value);
if (v) {
- partial.push(quote(k) + (gap ? ': ' : ':') + v);
+ partial.push(quote(k) + (
+ gap
+ ? ': '
+ : ':'
+ ) + v);
}
}
}
@@ -338,8 +366,8 @@ if (typeof JSON !== 'object') {
v = partial.length === 0
? '{}'
: gap
- ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
- : '{' + partial.join(',') + '}';
+ ? '{\n' + gap + partial.join(',\n' + gap) + '\n' + mind + '}'
+ : '{' + partial.join(',') + '}';
gap = mind;
return v;
}
@@ -348,14 +376,13 @@ if (typeof JSON !== 'object') {
// If the JSON object does not yet have a stringify method, give it one.
if (typeof JSON.stringify !== 'function') {
- escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
meta = { // table of character substitutions
'\b': '\\b',
'\t': '\\t',
'\n': '\\n',
'\f': '\\f',
'\r': '\\r',
- '"' : '\\"',
+ '"': '\\"',
'\\': '\\\\'
};
JSON.stringify = function (value, replacer, space) {
@@ -405,7 +432,6 @@ if (typeof JSON !== 'object') {
// If the JSON object does not yet have a parse method, give it one.
if (typeof JSON.parse !== 'function') {
- cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
JSON.parse = function (text, reviver) {
// The parse method takes a text and an optional reviver function, and returns
@@ -440,11 +466,11 @@ if (typeof JSON !== 'object') {
// incorrectly, either silently deleting them, or treating them as line endings.
text = String(text);
- cx.lastIndex = 0;
- if (cx.test(text)) {
- text = text.replace(cx, function (a) {
+ rx_dangerous.lastIndex = 0;
+ if (rx_dangerous.test(text)) {
+ text = text.replace(rx_dangerous, function (a) {
return '\\u' +
- ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+ ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
});
}
@@ -461,10 +487,14 @@ if (typeof JSON !== 'object') {
// we look to see that the remaining characters are only whitespace or ']' or
// ',' or ':' or '{' or '}'. If that is so, then the text is safe for eval.
- if (/^[\],:{}\s]*$/
- .test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
- .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
- .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
+ if (
+ rx_one.test(
+ text
+ .replace(rx_two, '@')
+ .replace(rx_three, ']')
+ .replace(rx_four, '')
+ )
+ ) {
// In the third stage we use the eval function to compile the text into a
// JavaScript structure. The '{' operator is subject to a syntactic ambiguity
diff --git a/resources/lib/mustache/LICENSE b/resources/lib/mustache/LICENSE
new file mode 100644
index 00000000..aa1b8316
--- /dev/null
+++ b/resources/lib/mustache/LICENSE
@@ -0,0 +1,10 @@
+The MIT License
+
+Copyright (c) 2009 Chris Wanstrath (Ruby)
+Copyright (c) 2010-2014 Jan Lehnardt (JavaScript)
+
+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/oojs-ui/i18n/af.json b/resources/lib/oojs-ui/i18n/af.json
index 6f79e370..67ec517d 100644
--- a/resources/lib/oojs-ui/i18n/af.json
+++ b/resources/lib/oojs-ui/i18n/af.json
@@ -1,7 +1,8 @@
{
"@metadata": {
"authors": [
- "Naudefj"
+ "Naudefj",
+ "Fwolff"
]
},
"ooui-outline-control-move-down": "Skuif item af",
@@ -15,5 +16,8 @@
"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"
+ "ooui-dialog-process-continue": "Gaan voort",
+ "ooui-selectfile-button-select": "Kies 'n lêer",
+ "ooui-selectfile-placeholder": "Geen lêer is gekies nie",
+ "ooui-selectfile-dragdrop-placeholder": "Laat val die lêer hier"
}
diff --git a/resources/lib/oojs-ui/i18n/ar.json b/resources/lib/oojs-ui/i18n/ar.json
index 058a1491..610e1eee 100644
--- a/resources/lib/oojs-ui/i18n/ar.json
+++ b/resources/lib/oojs-ui/i18n/ar.json
@@ -10,7 +10,9 @@
"زكريا",
"مشعل الحربي",
"ترجمان05",
- "Abanima"
+ "Abanima",
+ "محمد أحمد عبد الفتاح",
+ "Hiba Alshawi"
]
},
"ooui-outline-control-move-down": "انقل العنصر للأسفل",
@@ -24,5 +26,9 @@
"ooui-dialog-process-error": "حدث خطأ",
"ooui-dialog-process-dismiss": "أغلق",
"ooui-dialog-process-retry": "حاول مرة أخرى",
- "ooui-dialog-process-continue": "استمر"
+ "ooui-dialog-process-continue": "استمر",
+ "ooui-selectfile-button-select": "أختر ملف",
+ "ooui-selectfile-not-supported": "تحديد الملفات غير مدعوم",
+ "ooui-selectfile-placeholder": "لم يختر أي ملف",
+ "ooui-selectfile-dragdrop-placeholder": "ترك ملف هنا"
}
diff --git a/resources/lib/oojs-ui/i18n/arq.json b/resources/lib/oojs-ui/i18n/arq.json
index 80987818..61eb3844 100644
--- a/resources/lib/oojs-ui/i18n/arq.json
+++ b/resources/lib/oojs-ui/i18n/arq.json
@@ -8,9 +8,14 @@
"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": "واصل",
+ "ooui-selectfile-not-supported": "تحديد الفيشيات ما هوش محدد",
+ "ooui-selectfile-placeholder": "ما اختاريتش حتا ملف"
}
diff --git a/resources/lib/oojs-ui/i18n/as.json b/resources/lib/oojs-ui/i18n/as.json
new file mode 100644
index 00000000..50532809
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/as.json
@@ -0,0 +1,25 @@
+{
+ "@metadata": {
+ "authors": [
+ "Gitartha.bordoloi",
+ "Dibya Dutta",
+ "IKHazarika"
+ ]
+ },
+ "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": "অব্যাহত ৰাখক",
+ "ooui-selectfile-button-select": "ফাইল নিৰ্বাচন কৰক",
+ "ooui-selectfile-not-supported": "নথি নিৰ্বাচন সমৰ্থন কৰা নাই",
+ "ooui-selectfile-placeholder": "কোনো নথি নিৰ্বাচিত কৰা হোৱা নাই",
+ "ooui-selectfile-dragdrop-placeholder": "ইয়াত ফাইল এৰক"
+}
diff --git a/resources/lib/oojs-ui/i18n/ast.json b/resources/lib/oojs-ui/i18n/ast.json
index 87d7688a..11761c6c 100644
--- a/resources/lib/oojs-ui/i18n/ast.json
+++ b/resources/lib/oojs-ui/i18n/ast.json
@@ -10,9 +10,16 @@
"ooui-outline-control-move-up": "Mover arriba l'elementu",
"ooui-outline-control-remove": "Desaniciar elementu",
"ooui-toolbar-more": "Más",
+ "ooui-toolgroup-expand": "Más",
+ "ooui-toolgroup-collapse": "Menos",
"ooui-dialog-message-accept": "Aceutar",
"ooui-dialog-message-reject": "Encaboxar",
"ooui-dialog-process-error": "Daqué funcionó mal",
"ooui-dialog-process-dismiss": "Descartar",
- "ooui-dialog-process-retry": "Vuelvi a intentalo"
+ "ooui-dialog-process-retry": "Vuelvi a intentalo",
+ "ooui-dialog-process-continue": "Siguir",
+ "ooui-selectfile-button-select": "Seleicionar un ficheru",
+ "ooui-selectfile-not-supported": "Nun hai encontu pa la seleición de ficheros",
+ "ooui-selectfile-placeholder": "Nun se seleicionó nengún ficheru",
+ "ooui-selectfile-dragdrop-placeholder": "Soltar el ficheru equí"
}
diff --git a/resources/lib/oojs-ui/i18n/be-tarask.json b/resources/lib/oojs-ui/i18n/be-tarask.json
index c5475f85..3548239a 100644
--- a/resources/lib/oojs-ui/i18n/be-tarask.json
+++ b/resources/lib/oojs-ui/i18n/be-tarask.json
@@ -4,10 +4,23 @@
"EugeneZelenko",
"Wizardist",
"Чаховіч Уладзіслаў",
- "Zedlik"
+ "Zedlik",
+ "Red Winged Duck",
+ "Renessaince"
]
},
- "ooui-outline-control-move-down": "Перасунуць ніжэй",
- "ooui-outline-control-move-up": "Перасунуць вышэй",
- "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-process-dismiss": "Прапусьціць",
+ "ooui-dialog-process-retry": "Паспрабаваць зноў",
+ "ooui-dialog-process-continue": "Працягваць",
+ "ooui-selectfile-not-supported": "Выбар файлу не падтрымліваецца",
+ "ooui-selectfile-placeholder": "Ніводзін файл не абраны"
}
diff --git a/resources/lib/oojs-ui/i18n/be.json b/resources/lib/oojs-ui/i18n/be.json
index fb0f6880..7db7547b 100644
--- a/resources/lib/oojs-ui/i18n/be.json
+++ b/resources/lib/oojs-ui/i18n/be.json
@@ -2,9 +2,22 @@
"@metadata": {
"authors": [
"Чаховіч Уладзіслаў",
- "Artificial123"
+ "Artificial123",
+ "Goshaproject"
]
},
+ "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-message-reject": "Адмяніць",
+ "ooui-dialog-process-error": "Штось пайшло не так…",
+ "ooui-dialog-process-dismiss": "Прапусціць",
+ "ooui-dialog-process-retry": "Паспрабаваць яшчэ раз",
+ "ooui-dialog-process-continue": "Працягнуць",
+ "ooui-selectfile-not-supported": "Выбраны файл не падтрымліваецца",
+ "ooui-selectfile-placeholder": "Файл не выбраны"
}
diff --git a/resources/lib/oojs-ui/i18n/bg.json b/resources/lib/oojs-ui/i18n/bg.json
index 02d95b52..dce3593c 100644
--- a/resources/lib/oojs-ui/i18n/bg.json
+++ b/resources/lib/oojs-ui/i18n/bg.json
@@ -4,9 +4,18 @@
"DCLXVI",
"Hristofor.mirchev",
"පසිඳු කාවින්ද",
- "Mitzev"
+ "Mitzev",
+ "Aquilax"
]
},
"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/bn.json b/resources/lib/oojs-ui/i18n/bn.json
index 1cfa6c45..02d57e0c 100644
--- a/resources/lib/oojs-ui/i18n/bn.json
+++ b/resources/lib/oojs-ui/i18n/bn.json
@@ -8,7 +8,8 @@
"Runab",
"Sayak Sarkar",
"Aftabuzzaman",
- "RYasmeen (WMF)"
+ "RYasmeen (WMF)",
+ "NahidSultan"
]
},
"ooui-outline-control-move-down": "আইটেম নিচে স্থানান্তর",
@@ -22,5 +23,9 @@
"ooui-dialog-process-error": "কিছু একটায় ত্রুটি হয়েছে",
"ooui-dialog-process-dismiss": "বাতিল করুন",
"ooui-dialog-process-retry": "আবার চেষ্টা করুন",
- "ooui-dialog-process-continue": "অগ্রসর হোন"
+ "ooui-dialog-process-continue": "অগ্রসর হোন",
+ "ooui-selectfile-button-select": "একটি ফাইল নির্বাচন করুন",
+ "ooui-selectfile-not-supported": "চিত্র নির্বাচন সমর্থন করছে না।",
+ "ooui-selectfile-placeholder": " কোন চিত্র নির্বাচিত হয়নি।",
+ "ooui-selectfile-dragdrop-placeholder": "এখানে ফাইল ছাড়ুন"
}
diff --git a/resources/lib/oojs-ui/i18n/bs.json b/resources/lib/oojs-ui/i18n/bs.json
index 130bd8e5..d6f61ae5 100644
--- a/resources/lib/oojs-ui/i18n/bs.json
+++ b/resources/lib/oojs-ui/i18n/bs.json
@@ -1,10 +1,11 @@
{
"@metadata": {
"authors": [
- "DzWiki"
+ "DzWiki",
+ "Semso98"
]
},
- "ooui-outline-control-move-down": "Premjesti stavku dole",
+ "ooui-outline-control-move-down": "Premjesti stavku dolje",
"ooui-outline-control-move-up": "Premjesti stavku gore",
"ooui-outline-control-remove": "Ukloni stavku",
"ooui-toolbar-more": "Više",
diff --git a/resources/lib/oojs-ui/i18n/ca.json b/resources/lib/oojs-ui/i18n/ca.json
index ce3afa43..3077b605 100644
--- a/resources/lib/oojs-ui/i18n/ca.json
+++ b/resources/lib/oojs-ui/i18n/ca.json
@@ -10,7 +10,10 @@
"Vriullop",
"Toniher",
"Edustus",
- "Davidpar"
+ "Davidpar",
+ "Maceleiro",
+ "Kippelboy",
+ "Macofe"
]
},
"ooui-outline-control-move-down": "Baixa l'element",
@@ -24,5 +27,9 @@
"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-continue": "Continua"
+ "ooui-dialog-process-continue": "Continua",
+ "ooui-selectfile-button-select": "Seleccioneu un fitxer",
+ "ooui-selectfile-not-supported": "El tipus de fitxer no és compatible",
+ "ooui-selectfile-placeholder": "No s'ha seleccionat cap fitxer",
+ "ooui-selectfile-dragdrop-placeholder": "Deixeu-hi anar el fitxer (o feu clic a navega)"
}
diff --git a/resources/lib/oojs-ui/i18n/ckb.json b/resources/lib/oojs-ui/i18n/ckb.json
index 0c66619d..d2a998c0 100644
--- a/resources/lib/oojs-ui/i18n/ckb.json
+++ b/resources/lib/oojs-ui/i18n/ckb.json
@@ -3,9 +3,18 @@
"authors": [
"Calak",
"Muhammed taha",
- "Serwan"
+ "Serwan",
+ "Pirehelokan"
]
},
+ "ooui-toolbar-more": "زیاتر",
+ "ooui-toolgroup-expand": "زیاتر",
+ "ooui-toolgroup-collapse": "کەمتر",
"ooui-dialog-message-accept": "باشە",
- "ooui-dialog-message-reject": "پاشگەزبوونەوە"
+ "ooui-dialog-message-reject": "پاشگەزبوونەوە",
+ "ooui-dialog-process-error": "ھەڵەیەک ڕووی داوە",
+ "ooui-dialog-process-dismiss": "لێگەڕان",
+ "ooui-dialog-process-retry": "دیسان ھەوڵ بدە",
+ "ooui-dialog-process-continue": "درێژە بدە",
+ "ooui-selectfile-placeholder": "ھیچ فایلێک ھەڵنەبژێراوە"
}
diff --git a/resources/lib/oojs-ui/i18n/cs.json b/resources/lib/oojs-ui/i18n/cs.json
index 1db9aed5..0d86aa64 100644
--- a/resources/lib/oojs-ui/i18n/cs.json
+++ b/resources/lib/oojs-ui/i18n/cs.json
@@ -25,5 +25,7 @@
"ooui-dialog-process-error": "Něco se pokazilo",
"ooui-dialog-process-dismiss": "Zavřít",
"ooui-dialog-process-retry": "Zkusit znovu",
- "ooui-dialog-process-continue": "Pokračovat"
+ "ooui-dialog-process-continue": "Pokračovat",
+ "ooui-selectfile-not-supported": "Výběr souboru není podporován",
+ "ooui-selectfile-placeholder": "Nebyl vybrán žádný soubor"
}
diff --git a/resources/lib/oojs-ui/i18n/cu.json b/resources/lib/oojs-ui/i18n/cu.json
index aa916af0..d627de06 100644
--- a/resources/lib/oojs-ui/i18n/cu.json
+++ b/resources/lib/oojs-ui/i18n/cu.json
@@ -5,5 +5,6 @@
]
},
"ooui-toolbar-more": "вѧщє",
- "ooui-toolgroup-expand": "вѧщє"
+ "ooui-toolgroup-expand": "вѧщє",
+ "ooui-dialog-process-error": "нѣчьто ꙁълѣ сѧ авило"
}
diff --git a/resources/lib/oojs-ui/i18n/da.json b/resources/lib/oojs-ui/i18n/da.json
index 0b847be1..30e3efae 100644
--- a/resources/lib/oojs-ui/i18n/da.json
+++ b/resources/lib/oojs-ui/i18n/da.json
@@ -7,10 +7,13 @@
"Laketown",
"Palnatoke",
"Simeondahl",
- "Tehnix"
+ "Tehnix",
+ "Macofe"
]
},
"ooui-outline-control-move-down": "Flyt ned",
"ooui-outline-control-move-up": "Flyt op",
- "ooui-toolbar-more": "Mere"
+ "ooui-toolbar-more": "Mere",
+ "ooui-toolgroup-expand": "Mere",
+ "ooui-dialog-process-continue": "Fortsæt"
}
diff --git a/resources/lib/oojs-ui/i18n/de.json b/resources/lib/oojs-ui/i18n/de.json
index 15624fd4..b48dfb5e 100644
--- a/resources/lib/oojs-ui/i18n/de.json
+++ b/resources/lib/oojs-ui/i18n/de.json
@@ -24,5 +24,9 @@
"ooui-dialog-process-error": "Etwas ist schief gelaufen",
"ooui-dialog-process-dismiss": "Ausblenden",
"ooui-dialog-process-retry": "Erneut versuchen",
- "ooui-dialog-process-continue": "Fortfahren"
+ "ooui-dialog-process-continue": "Fortfahren",
+ "ooui-selectfile-button-select": "Eine Datei auswählen",
+ "ooui-selectfile-not-supported": "Die Dateiauswahl wird nicht unterstützt",
+ "ooui-selectfile-placeholder": "Keine Datei ausgewählt",
+ "ooui-selectfile-dragdrop-placeholder": "Dateien hier ablegen"
}
diff --git a/resources/lib/oojs-ui/i18n/dty.json b/resources/lib/oojs-ui/i18n/dty.json
new file mode 100644
index 00000000..21742b69
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/dty.json
@@ -0,0 +1,18 @@
+{
+ "@metadata": {
+ "authors": [
+ "जनक राज भट्ट"
+ ]
+ },
+ "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-dismiss": "खारेज गद्दे",
+ "ooui-dialog-process-retry": "दोसरया प्रयास गर",
+ "ooui-dialog-process-continue": "जारी राख्या"
+}
diff --git a/resources/lib/oojs-ui/i18n/el.json b/resources/lib/oojs-ui/i18n/el.json
index 6fb7dbad..85384179 100644
--- a/resources/lib/oojs-ui/i18n/el.json
+++ b/resources/lib/oojs-ui/i18n/el.json
@@ -8,7 +8,8 @@
"Geraki",
"Glavkos",
"Nikosguard",
- "Tifa93"
+ "Tifa93",
+ "Stam.nikos"
]
},
"ooui-outline-control-move-down": "Μετακίνηση στοιχείου προς τα κάτω",
@@ -22,5 +23,8 @@
"ooui-dialog-process-error": "Κάτι πήγε στραβά",
"ooui-dialog-process-dismiss": "Απόρριψη",
"ooui-dialog-process-retry": "Δοκιμάστε ξανά",
- "ooui-dialog-process-continue": "Συνέχεια"
+ "ooui-dialog-process-continue": "Συνέχεια",
+ "ooui-selectfile-not-supported": "Επιλογή αρχείου δεν υποστηρίζεται",
+ "ooui-selectfile-placeholder": "Κανένα αρχείο δεν είναι επιλεγμένο",
+ "ooui-selectfile-dragdrop-placeholder": "Σύρετε το αρχείο εδώ"
}
diff --git a/resources/lib/oojs-ui/i18n/en-ca.json b/resources/lib/oojs-ui/i18n/en-ca.json
new file mode 100644
index 00000000..1a8e31be
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/en-ca.json
@@ -0,0 +1,22 @@
+{
+ "@metadata": {
+ "authors": [
+ "Skyllful"
+ ]
+ },
+ "ooui-outline-control-move-down": "Move item down",
+ "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": "Less",
+ "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-continue": "Continue",
+ "ooui-selectfile-not-supported": "File(s) not supported",
+ "ooui-selectfile-placeholder": "No file selected",
+ "ooui-selectfile-dragdrop-placeholder": "Drop file here (or click to browse your computer)"
+}
diff --git a/resources/lib/oojs-ui/i18n/en.json b/resources/lib/oojs-ui/i18n/en.json
index 1db3fd85..be008321 100644
--- a/resources/lib/oojs-ui/i18n/en.json
+++ b/resources/lib/oojs-ui/i18n/en.json
@@ -27,5 +27,9 @@
"ooui-dialog-process-error": "Something went wrong",
"ooui-dialog-process-dismiss": "Dismiss",
"ooui-dialog-process-retry": "Try again",
- "ooui-dialog-process-continue": "Continue"
+ "ooui-dialog-process-continue": "Continue",
+ "ooui-selectfile-button-select": "Select a file",
+ "ooui-selectfile-not-supported": "File selection is not supported",
+ "ooui-selectfile-placeholder": "No file is selected",
+ "ooui-selectfile-dragdrop-placeholder": "Drop file here"
}
diff --git a/resources/lib/oojs-ui/i18n/eo.json b/resources/lib/oojs-ui/i18n/eo.json
index 8d9714c6..e7895650 100644
--- a/resources/lib/oojs-ui/i18n/eo.json
+++ b/resources/lib/oojs-ui/i18n/eo.json
@@ -4,10 +4,23 @@
"Happy5214",
"KuboF",
"Shirayuki",
- "Yekrats"
+ "Yekrats",
+ "Kvardek du"
]
},
"ooui-outline-control-move-down": "Movi eron suben",
"ooui-outline-control-move-up": "Movi eron supren",
- "ooui-toolbar-more": "Pli"
+ "ooui-outline-control-remove": "Forigi eron",
+ "ooui-toolbar-more": "Pli",
+ "ooui-toolgroup-expand": "Pli",
+ "ooui-toolgroup-collapse": "Mapli",
+ "ooui-dialog-message-accept": "Bone",
+ "ooui-dialog-message-reject": "Nuligi",
+ "ooui-dialog-process-error": "Io rompiĝis",
+ "ooui-dialog-process-dismiss": "Elimini",
+ "ooui-dialog-process-retry": "Reprovi",
+ "ooui-dialog-process-continue": "Daŭrigi",
+ "ooui-selectfile-button-select": "Elekti dosieron",
+ "ooui-selectfile-not-supported": "Dosieroselekto ne estas subtenata.",
+ "ooui-selectfile-placeholder": "Vi ne selektis dosieron"
}
diff --git a/resources/lib/oojs-ui/i18n/es.json b/resources/lib/oojs-ui/i18n/es.json
index 915791e6..fa11a362 100644
--- a/resources/lib/oojs-ui/i18n/es.json
+++ b/resources/lib/oojs-ui/i18n/es.json
@@ -29,5 +29,9 @@
"ooui-dialog-process-error": "Algo salió mal",
"ooui-dialog-process-dismiss": "Descartar",
"ooui-dialog-process-retry": "Intentar de nuevo",
- "ooui-dialog-process-continue": "Continuar"
+ "ooui-dialog-process-continue": "Continuar",
+ "ooui-selectfile-button-select": "Selecciona un archivo",
+ "ooui-selectfile-not-supported": "No se admite la selección de archivos",
+ "ooui-selectfile-placeholder": "Ningún archivo seleccionado",
+ "ooui-selectfile-dragdrop-placeholder": "Suelta el archivo aquí"
}
diff --git a/resources/lib/oojs-ui/i18n/et.json b/resources/lib/oojs-ui/i18n/et.json
index 6a212b6b..59b7ccd9 100644
--- a/resources/lib/oojs-ui/i18n/et.json
+++ b/resources/lib/oojs-ui/i18n/et.json
@@ -2,7 +2,8 @@
"@metadata": {
"authors": [
"Avjoska",
- "Pikne"
+ "Pikne",
+ "Suwa"
]
},
"ooui-outline-control-move-down": "Liiguta üksust allapoole",
@@ -16,5 +17,9 @@
"ooui-dialog-process-error": "Midagi läks valesti",
"ooui-dialog-process-dismiss": "Hülga",
"ooui-dialog-process-retry": "Proovi uuesti",
- "ooui-dialog-process-continue": "Jätka"
+ "ooui-dialog-process-continue": "Jätka",
+ "ooui-selectfile-button-select": "Vali fail",
+ "ooui-selectfile-not-supported": "Faili valiku tugi puudub",
+ "ooui-selectfile-placeholder": "Faili ei ole valitud",
+ "ooui-selectfile-dragdrop-placeholder": "Lohista fail siia"
}
diff --git a/resources/lib/oojs-ui/i18n/eu.json b/resources/lib/oojs-ui/i18n/eu.json
index e947582d..e5073251 100644
--- a/resources/lib/oojs-ui/i18n/eu.json
+++ b/resources/lib/oojs-ui/i18n/eu.json
@@ -4,17 +4,23 @@
"An13sa",
"Unai Fdz. de Betoño",
"Xabier Armendaritz",
- "Subi"
+ "Subi",
+ "Sator"
]
},
"ooui-outline-control-move-down": "Mugitu itema beherantz",
"ooui-outline-control-move-up": "Mugitu itema gorantz",
+ "ooui-outline-control-remove": "Elementua kendu",
"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-dismiss": "Utzi",
"ooui-dialog-process-retry": "Saiatu berriro",
- "ooui-dialog-process-continue": "Jarraitu"
+ "ooui-dialog-process-continue": "Jarraitu",
+ "ooui-selectfile-button-select": "Fitxategi bat aukeratu",
+ "ooui-selectfile-not-supported": "Fitxategi aukeraketa ez da onartzen",
+ "ooui-selectfile-placeholder": "Ez da fitxategirik hautatu"
}
diff --git a/resources/lib/oojs-ui/i18n/fa.json b/resources/lib/oojs-ui/i18n/fa.json
index 7cfcfa21..0375c8eb 100644
--- a/resources/lib/oojs-ui/i18n/fa.json
+++ b/resources/lib/oojs-ui/i18n/fa.json
@@ -11,7 +11,10 @@
"Taha",
"درفش کاویانی",
"Armin1392",
- "Alirezaaa"
+ "Alirezaaa",
+ "Leyth",
+ "الناز",
+ "فلورانس"
]
},
"ooui-outline-control-move-down": "انتقال مورد به پایین",
@@ -23,7 +26,11 @@
"ooui-dialog-message-accept": "تأیید",
"ooui-dialog-message-reject": "لغو",
"ooui-dialog-process-error": "مشکلی وجود دارد",
- "ooui-dialog-process-dismiss": "نپذیرفتن",
- "ooui-dialog-process-retry": "دوباره امتحان کن",
- "ooui-dialog-process-continue": "ادامه"
+ "ooui-dialog-process-dismiss": "رد",
+ "ooui-dialog-process-retry": "دوباره امتحان کنید",
+ "ooui-dialog-process-continue": "ادامه",
+ "ooui-selectfile-button-select": "یک فایل انتخاب کنید",
+ "ooui-selectfile-not-supported": "انتخاب پرونده پشتیبانی نمی‌شود",
+ "ooui-selectfile-placeholder": "هیچ پرونده‌ای انتخاب نشده است",
+ "ooui-selectfile-dragdrop-placeholder": "فایل را اینجا رها کنید"
}
diff --git a/resources/lib/oojs-ui/i18n/fi.json b/resources/lib/oojs-ui/i18n/fi.json
index 3fb4110c..bdf015f9 100644
--- a/resources/lib/oojs-ui/i18n/fi.json
+++ b/resources/lib/oojs-ui/i18n/fi.json
@@ -13,19 +13,23 @@
"Silvonen",
"Skalman",
"Stryn",
- "VezonThunder"
+ "VezonThunder",
+ "Alluk."
]
},
"ooui-outline-control-move-down": "Siirrä kohdetta alaspäin",
"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-toolgroup-expand": "Näytä lisää",
+ "ooui-toolgroup-collapse": "Näytä vähemmän",
"ooui-dialog-message-accept": "OK",
- "ooui-dialog-message-reject": "Peruuta",
+ "ooui-dialog-message-reject": "Peru",
"ooui-dialog-process-error": "Jokin meni pieleen",
"ooui-dialog-process-dismiss": "Hylkää",
"ooui-dialog-process-retry": "Yritä uudelleen",
- "ooui-dialog-process-continue": "Jatka"
+ "ooui-dialog-process-continue": "Jatka",
+ "ooui-selectfile-not-supported": "Tiedoston valitsemista ei tueta",
+ "ooui-selectfile-placeholder": "Tiedostoa ei ole valittu",
+ "ooui-selectfile-dragdrop-placeholder": "Pudota tiedosto (tai selaa tiedostoja napsauttamalla)"
}
diff --git a/resources/lib/oojs-ui/i18n/fr.json b/resources/lib/oojs-ui/i18n/fr.json
index 9144cb01..92015a4f 100644
--- a/resources/lib/oojs-ui/i18n/fr.json
+++ b/resources/lib/oojs-ui/i18n/fr.json
@@ -27,19 +27,25 @@
"Verdy p",
"Wyz",
"SnowedEarth",
- "Jdforrester"
+ "Jdforrester",
+ "Wladek92",
+ "Harmonia Amanda"
]
},
- "ooui-outline-control-move-down": "Faire descendre l’élément",
- "ooui-outline-control-move-up": "Faire monter l’élément",
+ "ooui-outline-control-move-down": "Descendre l’élément",
+ "ooui-outline-control-move-up": "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-error": "Quelque chose s'est mal passé",
"ooui-dialog-process-dismiss": "Rejeter",
- "ooui-dialog-process-retry": "Réessayez",
- "ooui-dialog-process-continue": "Continuer"
+ "ooui-dialog-process-retry": "Réessayer",
+ "ooui-dialog-process-continue": "Continuer",
+ "ooui-selectfile-button-select": "Sélectionner un fichier",
+ "ooui-selectfile-not-supported": "La sélection de fichier n’est pas prise en charge",
+ "ooui-selectfile-placeholder": "Aucun fichier sélectionné",
+ "ooui-selectfile-dragdrop-placeholder": "Déposer le fichier ici"
}
diff --git a/resources/lib/oojs-ui/i18n/gl.json b/resources/lib/oojs-ui/i18n/gl.json
index a4339f47..4cb28399 100644
--- a/resources/lib/oojs-ui/i18n/gl.json
+++ b/resources/lib/oojs-ui/i18n/gl.json
@@ -18,5 +18,9 @@
"ooui-dialog-process-error": "Algo foi mal",
"ooui-dialog-process-dismiss": "Agochar",
"ooui-dialog-process-retry": "Inténteo de novo",
- "ooui-dialog-process-continue": "Continuar"
+ "ooui-dialog-process-continue": "Continuar",
+ "ooui-selectfile-button-select": "Seleccionar un ficheiro",
+ "ooui-selectfile-not-supported": "Non está soportada a selección de ficheiros",
+ "ooui-selectfile-placeholder": "Non se seleccionou ningún ficheiro",
+ "ooui-selectfile-dragdrop-placeholder": "Solte un ficheiro aquí"
}
diff --git a/resources/lib/oojs-ui/i18n/glk.json b/resources/lib/oojs-ui/i18n/glk.json
new file mode 100644
index 00000000..9b15046f
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/glk.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "V6rg"
+ ]
+ },
+ "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": "سره",
+ "ooui-selectfile-button-select": "ىکته فاىله دؤجين بۊکۊنين",
+ "ooui-selectfile-not-supported": "نشأنهىکته فاىله دؤجين گۊدن",
+ "ooui-selectfile-placeholder": "هيچ فاىلي دؤجين نۊبؤ",
+ "ooui-selectfile-dragdrop-placeholder": "فاىله ائره فدي"
+}
diff --git a/resources/lib/oojs-ui/i18n/gu.json b/resources/lib/oojs-ui/i18n/gu.json
index 2d8315bf..5c48b9ef 100644
--- a/resources/lib/oojs-ui/i18n/gu.json
+++ b/resources/lib/oojs-ui/i18n/gu.json
@@ -3,15 +3,23 @@
"authors": [
"Ashok modhvadia",
"KartikMistry",
- "The Discoverer"
+ "The Discoverer",
+ "NehalDaveND",
+ "Dsvyas"
]
},
"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-retry": "ફરી પ્રયત્ન કરો"
+ "ooui-dialog-process-dismiss": "વિસર્જન",
+ "ooui-dialog-process-retry": "ફરી પ્રયત્ન કરો",
+ "ooui-dialog-process-continue": "ચાલુ રાખો",
+ "ooui-selectfile-not-supported": "ફાઇલ પસંદગીની જોગવાઈ નથી",
+ "ooui-selectfile-placeholder": "કોઇ ફાઇલ પસંદ નથી કરાઈ"
}
diff --git a/resources/lib/oojs-ui/i18n/he.json b/resources/lib/oojs-ui/i18n/he.json
index cadc416c..650d67dd 100644
--- a/resources/lib/oojs-ui/i18n/he.json
+++ b/resources/lib/oojs-ui/i18n/he.json
@@ -26,5 +26,9 @@
"ooui-dialog-process-error": "משהו השתבש",
"ooui-dialog-process-dismiss": "לוותר",
"ooui-dialog-process-retry": "לנסות שוב",
- "ooui-dialog-process-continue": "המשך"
+ "ooui-dialog-process-continue": "המשך",
+ "ooui-selectfile-button-select": "נא לבחור קובץ",
+ "ooui-selectfile-not-supported": "בחירת קבצים אינה נתמכת",
+ "ooui-selectfile-placeholder": "לא נבחר שום קובץ",
+ "ooui-selectfile-dragdrop-placeholder": "נא לשחרר את הקובץ כאן"
}
diff --git a/resources/lib/oojs-ui/i18n/hi.json b/resources/lib/oojs-ui/i18n/hi.json
index ce86aaab..573096f3 100644
--- a/resources/lib/oojs-ui/i18n/hi.json
+++ b/resources/lib/oojs-ui/i18n/hi.json
@@ -6,7 +6,8 @@
"Rajesh",
"Siddhartha Ghai",
"Goelujjwal",
- "Ankita-ks"
+ "Ankita-ks",
+ "Param Mudgal"
]
},
"ooui-outline-control-move-down": "प्रविष्टि नीचे ले जाएँ",
@@ -20,5 +21,7 @@
"ooui-dialog-process-error": "कुछ गलत हुअा है",
"ooui-dialog-process-dismiss": "ख़ारिज करें",
"ooui-dialog-process-retry": "पुनः प्रयास करें",
- "ooui-dialog-process-continue": "जारी रखें"
+ "ooui-dialog-process-continue": "जारी रखें",
+ "ooui-selectfile-not-supported": "फ़ाइल का चयन समर्थित नहीं है",
+ "ooui-selectfile-placeholder": "कोई फाइल चुनी नही गई हेै"
}
diff --git a/resources/lib/oojs-ui/i18n/hrx.json b/resources/lib/oojs-ui/i18n/hrx.json
new file mode 100644
index 00000000..1534af76
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/hrx.json
@@ -0,0 +1,12 @@
+{
+ "@metadata": {
+ "authors": [
+ "Midnight Gambler"
+ ]
+ },
+ "ooui-toolbar-more": "Meahr",
+ "ooui-toolgroup-expand": "Meahr",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Abbreche",
+ "ooui-dialog-process-dismiss": "Ausblenne"
+}
diff --git a/resources/lib/oojs-ui/i18n/hu-formal.json b/resources/lib/oojs-ui/i18n/hu-formal.json
new file mode 100644
index 00000000..34aa0ae6
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/hu-formal.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Misibacsi"
+ ]
+ },
+ "ooui-outline-control-move-down": "Elem mozgatása lefelé",
+ "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": "Tovább",
+ "ooui-toolgroup-collapse": "Kevesebb",
+ "ooui-dialog-message-accept": "Rendben",
+ "ooui-dialog-message-reject": "Mégse",
+ "ooui-dialog-process-error": "Valami elromlott.",
+ "ooui-dialog-process-dismiss": "Mégse",
+ "ooui-dialog-process-retry": "Próbálja újra",
+ "ooui-dialog-process-continue": "Folytatás",
+ "ooui-selectfile-not-supported": "A fájl kiválasztása nincs támogatva",
+ "ooui-selectfile-placeholder": "Nincs fájl kiválasztva"
+}
diff --git a/resources/lib/oojs-ui/i18n/hu.json b/resources/lib/oojs-ui/i18n/hu.json
index d50e62da..acd9d3b5 100644
--- a/resources/lib/oojs-ui/i18n/hu.json
+++ b/resources/lib/oojs-ui/i18n/hu.json
@@ -6,18 +6,22 @@
"Misibacsi",
"ViDam",
"Tacsipacsi",
- "Csega"
+ "Csega",
+ "Kishajnalka"
]
},
"ooui-outline-control-move-down": "Elem mozgatása lefelé",
"ooui-outline-control-move-up": "Elem mozgatása felfelé",
"ooui-outline-control-remove": "Elem eltávolítása",
- "ooui-toolbar-more": "Tovább...",
+ "ooui-toolbar-more": "Több",
"ooui-toolgroup-expand": "Több",
"ooui-toolgroup-collapse": "Kevesebb",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Mégse",
+ "ooui-dialog-process-error": "Valami elromlott",
"ooui-dialog-process-dismiss": "Elrejt",
"ooui-dialog-process-retry": "Próbáld újra",
- "ooui-dialog-process-continue": "Folytatás"
+ "ooui-dialog-process-continue": "Folytatás",
+ "ooui-selectfile-not-supported": "A fájl kiválasztása nincs támogatva",
+ "ooui-selectfile-placeholder": "Nincs fájl kiválasztva"
}
diff --git a/resources/lib/oojs-ui/i18n/hy.json b/resources/lib/oojs-ui/i18n/hy.json
index 2aaf4e46..c2b45a8b 100644
--- a/resources/lib/oojs-ui/i18n/hy.json
+++ b/resources/lib/oojs-ui/i18n/hy.json
@@ -3,7 +3,8 @@
"authors": [
"Vacio",
"Xelgen",
- "Դավիթ Սարոյան"
+ "Դավիթ Սարոյան",
+ "Vahe Gharakhanyan"
]
},
"ooui-outline-control-move-down": "Իջեցնել կետը",
@@ -17,5 +18,7 @@
"ooui-dialog-process-error": "Ինչ-որ սխալ է տեղի ունեցել",
"ooui-dialog-process-dismiss": "Փակել",
"ooui-dialog-process-retry": "Կրկին փորձել",
- "ooui-dialog-process-continue": "Շարունակել"
+ "ooui-dialog-process-continue": "Շարունակել",
+ "ooui-selectfile-not-supported": "Ֆայլի ընտրությունը չի պաշտպանվում",
+ "ooui-selectfile-placeholder": "Ֆայլն ընտրված չէ"
}
diff --git a/resources/lib/oojs-ui/i18n/ia.json b/resources/lib/oojs-ui/i18n/ia.json
index b374b6f6..ceb27c9f 100644
--- a/resources/lib/oojs-ui/i18n/ia.json
+++ b/resources/lib/oojs-ui/i18n/ia.json
@@ -8,9 +8,16 @@
"ooui-outline-control-move-up": "Displaciar elemento in alto",
"ooui-outline-control-remove": "Remover elemento",
"ooui-toolbar-more": "Plus",
+ "ooui-toolgroup-expand": "Plus",
+ "ooui-toolgroup-collapse": "Minus",
"ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Cancellar",
"ooui-dialog-process-error": "Qualcosa ha vadite mal",
"ooui-dialog-process-dismiss": "Clauder",
- "ooui-dialog-process-retry": "Reprobar"
+ "ooui-dialog-process-retry": "Reprobar",
+ "ooui-dialog-process-continue": "Continuar",
+ "ooui-selectfile-button-select": "Selige un file",
+ "ooui-selectfile-not-supported": "Le selection de files non es supportate",
+ "ooui-selectfile-placeholder": "Nulle file es seligite",
+ "ooui-selectfile-dragdrop-placeholder": "Depone file hic"
}
diff --git a/resources/lib/oojs-ui/i18n/id.json b/resources/lib/oojs-ui/i18n/id.json
index bd65e71a..400a4325 100644
--- a/resources/lib/oojs-ui/i18n/id.json
+++ b/resources/lib/oojs-ui/i18n/id.json
@@ -22,5 +22,7 @@
"ooui-dialog-process-error": "Ada yang tidak beres",
"ooui-dialog-process-dismiss": "Tutup",
"ooui-dialog-process-retry": "Coba lagi",
- "ooui-dialog-process-continue": "Lanjutkan"
+ "ooui-dialog-process-continue": "Lanjutkan",
+ "ooui-selectfile-not-supported": "Peilihan berkas tidak didukung",
+ "ooui-selectfile-placeholder": "Tidak ada berkas yang terpilih"
}
diff --git a/resources/lib/oojs-ui/i18n/ilo.json b/resources/lib/oojs-ui/i18n/ilo.json
index b37beae1..287c86d6 100644
--- a/resources/lib/oojs-ui/i18n/ilo.json
+++ b/resources/lib/oojs-ui/i18n/ilo.json
@@ -15,5 +15,7 @@
"ooui-dialog-process-error": "Adda madi a napasamak",
"ooui-dialog-process-dismiss": "Pugsayen",
"ooui-dialog-process-retry": "Padasen manen",
- "ooui-dialog-process-continue": "Agtuloy"
+ "ooui-dialog-process-continue": "Agtuloy",
+ "ooui-selectfile-not-supported": "Saan a masuportaran ti panagpili ti papeles",
+ "ooui-selectfile-placeholder": "Awan ti napili a papeles"
}
diff --git a/resources/lib/oojs-ui/i18n/is.json b/resources/lib/oojs-ui/i18n/is.json
index 3a4e1454..574c5927 100644
--- a/resources/lib/oojs-ui/i18n/is.json
+++ b/resources/lib/oojs-ui/i18n/is.json
@@ -16,5 +16,9 @@
"ooui-dialog-process-error": "Eitthvað mistókst",
"ooui-dialog-process-dismiss": "Loka",
"ooui-dialog-process-retry": "Reyna aftur",
- "ooui-dialog-process-continue": "Halda áfram"
+ "ooui-dialog-process-continue": "Halda áfram",
+ "ooui-selectfile-button-select": "Velja skrá",
+ "ooui-selectfile-not-supported": "Skráar val er ekki stutt.",
+ "ooui-selectfile-placeholder": "Engin skrá er valin",
+ "ooui-selectfile-dragdrop-placeholder": "Slepptu skránni hérna"
}
diff --git a/resources/lib/oojs-ui/i18n/it.json b/resources/lib/oojs-ui/i18n/it.json
index 0ff8af8f..68a25b5d 100644
--- a/resources/lib/oojs-ui/i18n/it.json
+++ b/resources/lib/oojs-ui/i18n/it.json
@@ -12,19 +12,26 @@
"Minerva Titani",
"Raoli",
"Una giornata uggiosa '94",
- "Ontsed"
+ "Ontsed",
+ "Alexmar983",
+ "Nemo bis",
+ "Jdforrester"
]
},
"ooui-outline-control-move-down": "Sposta in basso",
"ooui-outline-control-move-up": "Sposta in alto",
"ooui-outline-control-remove": "Rimuovi elemento",
"ooui-toolbar-more": "Altro",
- "ooui-toolgroup-expand": "Più",
+ "ooui-toolgroup-expand": "Altro",
"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-continue": "Continua"
+ "ooui-dialog-process-continue": "Continua",
+ "ooui-selectfile-button-select": "Seleziona un file",
+ "ooui-selectfile-not-supported": "La selezione del file non è supportata",
+ "ooui-selectfile-placeholder": "Nessun file è selezionato",
+ "ooui-selectfile-dragdrop-placeholder": "Posiziona i files qui"
}
diff --git a/resources/lib/oojs-ui/i18n/ja.json b/resources/lib/oojs-ui/i18n/ja.json
index ec86124e..d0df0274 100644
--- a/resources/lib/oojs-ui/i18n/ja.json
+++ b/resources/lib/oojs-ui/i18n/ja.json
@@ -6,7 +6,8 @@
"Penn Station",
"Shirayuki",
"Takot",
- "Los688"
+ "Los688",
+ "Sujiniku"
]
},
"ooui-outline-control-move-down": "項目を下に移動させる",
@@ -20,5 +21,9 @@
"ooui-dialog-process-error": "エラーが発生しました…",
"ooui-dialog-process-dismiss": "閉じる",
"ooui-dialog-process-retry": "もう一度お試しください",
- "ooui-dialog-process-continue": "続行"
+ "ooui-dialog-process-continue": "続行",
+ "ooui-selectfile-button-select": "ファイルを選択",
+ "ooui-selectfile-not-supported": "ファイルの選択はサポートされていません",
+ "ooui-selectfile-placeholder": "ファイルが選択されていません",
+ "ooui-selectfile-dragdrop-placeholder": "ファイルをここにドロップ"
}
diff --git a/resources/lib/oojs-ui/i18n/jv.json b/resources/lib/oojs-ui/i18n/jv.json
index 8827af38..677b1c3d 100644
--- a/resources/lib/oojs-ui/i18n/jv.json
+++ b/resources/lib/oojs-ui/i18n/jv.json
@@ -3,8 +3,22 @@
"authors": [
"Gleki",
"NoiX180",
- "Pras"
+ "Pras",
+ "Jadinegara"
]
},
- "ooui-outline-control-move-down": "Pindhahaken butir mangandhap"
+ "ooui-outline-control-move-down": "Pindhahaken butir mangandhap",
+ "ooui-outline-control-move-up": "Pindhah kara mêndhuwur",
+ "ooui-outline-control-remove": "Busak kara",
+ "ooui-toolbar-more": "Mênèh",
+ "ooui-toolgroup-expand": "Mênèh",
+ "ooui-toolgroup-collapse": "Suda",
+ "ooui-dialog-message-accept": "Oké",
+ "ooui-dialog-message-reject": "Batal",
+ "ooui-dialog-process-error": "Ana sing klèru",
+ "ooui-dialog-process-dismiss": "Tutup",
+ "ooui-dialog-process-retry": "Jajal manèh",
+ "ooui-dialog-process-continue": "Tutug",
+ "ooui-selectfile-not-supported": "Pilihan bêrkas ora disokong",
+ "ooui-selectfile-placeholder": "Ora ana bêrkas sing kapilih"
}
diff --git a/resources/lib/oojs-ui/i18n/ka.json b/resources/lib/oojs-ui/i18n/ka.json
index 60ef661b..f1a1a473 100644
--- a/resources/lib/oojs-ui/i18n/ka.json
+++ b/resources/lib/oojs-ui/i18n/ka.json
@@ -22,5 +22,7 @@
"ooui-dialog-process-error": "მოხდა რაღაც შეცდომა",
"ooui-dialog-process-dismiss": "დამალვა",
"ooui-dialog-process-retry": "კიდევ სცადეთ",
- "ooui-dialog-process-continue": "გაგრძელება"
+ "ooui-dialog-process-continue": "გაგრძელება",
+ "ooui-selectfile-not-supported": "ფაილის არჩევა არ არის მხარდაჭერილი",
+ "ooui-selectfile-placeholder": "ფაილი არ არის არჩეული"
}
diff --git a/resources/lib/oojs-ui/i18n/km.json b/resources/lib/oojs-ui/i18n/km.json
index c0d72c4f..e64889f4 100644
--- a/resources/lib/oojs-ui/i18n/km.json
+++ b/resources/lib/oojs-ui/i18n/km.json
@@ -1,11 +1,24 @@
{
"@metadata": {
"authors": [
- "Sovichet"
+ "Sovichet",
+ "គីមស៊្រុន"
]
},
- "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-process-dismiss": "បិទ",
+ "ooui-dialog-process-retry": "ព្យាយាមម្ដងទៀត",
+ "ooui-dialog-process-continue": "បន្ត",
+ "ooui-selectfile-button-select": "ជ្រើសរើសឯកសារ",
+ "ooui-selectfile-not-supported": "ការជ្រើសរើសឯកសារមិនអាចប្រើបានទេ",
+ "ooui-selectfile-placeholder": "គ្មានឯកសារណាមួយត្រូវបានជ្រើសរើស",
+ "ooui-selectfile-dragdrop-placeholder": "ទម្លាក់ឯកសារនៅទីនេះ"
}
diff --git a/resources/lib/oojs-ui/i18n/ko.json b/resources/lib/oojs-ui/i18n/ko.json
index 196dc2c3..38944173 100644
--- a/resources/lib/oojs-ui/i18n/ko.json
+++ b/resources/lib/oojs-ui/i18n/ko.json
@@ -9,17 +9,24 @@
"고기랑",
"Ryuch",
"Revi",
- "Infinity"
+ "Infinity",
+ "Hwangjy9"
]
},
"ooui-outline-control-move-down": "항목을 아래로 옮기기",
"ooui-outline-control-move-up": "항목을 위로 옮기기",
- "ooui-outline-control-remove": "항목 지우기",
+ "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": "계속",
+ "ooui-selectfile-button-select": "파일을 선택하세요",
+ "ooui-selectfile-not-supported": "파일 선택은 지원하지 않습니다",
+ "ooui-selectfile-placeholder": "선택한 파일 없음",
+ "ooui-selectfile-dragdrop-placeholder": "여기에 파일을 놓으세요"
}
diff --git a/resources/lib/oojs-ui/i18n/krc.json b/resources/lib/oojs-ui/i18n/krc.json
index ef92e49f..d4068c87 100644
--- a/resources/lib/oojs-ui/i18n/krc.json
+++ b/resources/lib/oojs-ui/i18n/krc.json
@@ -15,5 +15,7 @@
"ooui-dialog-process-error": "Не эсе да табсыз кетди",
"ooui-dialog-process-dismiss": "Джаб",
"ooui-dialog-process-retry": "Энтда сынаб кёр",
- "ooui-dialog-process-continue": "Бардыр"
+ "ooui-dialog-process-continue": "Бардыр",
+ "ooui-selectfile-not-supported": "Файл сайлау тутулмайды",
+ "ooui-selectfile-placeholder": "Бир файл да сайланмагъанды"
}
diff --git a/resources/lib/oojs-ui/i18n/krl.json b/resources/lib/oojs-ui/i18n/krl.json
new file mode 100644
index 00000000..6ff25ebe
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/krl.json
@@ -0,0 +1,10 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mashoi7"
+ ]
+ },
+ "ooui-toolbar-more": "Enämpi",
+ "ooui-toolgroup-expand": "Enämpi",
+ "ooui-toolgroup-collapse": "Vähempi"
+}
diff --git a/resources/lib/oojs-ui/i18n/ksh.json b/resources/lib/oojs-ui/i18n/ksh.json
index c975e825..f99c29fd 100644
--- a/resources/lib/oojs-ui/i18n/ksh.json
+++ b/resources/lib/oojs-ui/i18n/ksh.json
@@ -15,5 +15,8 @@
"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"
+ "ooui-dialog-process-continue": "Wigger maache",
+ "ooui-selectfile-button-select": "Söhg en Dattei uß",
+ "ooui-selectfile-not-supported": "Mer ogerschtözze et Datteij_Ußwähle nit.",
+ "ooui-selectfile-placeholder": "Kein Dattei es ußjewählt"
}
diff --git a/resources/lib/oojs-ui/i18n/ku-latn.json b/resources/lib/oojs-ui/i18n/ku-latn.json
index be9a8abd..94b46873 100644
--- a/resources/lib/oojs-ui/i18n/ku-latn.json
+++ b/resources/lib/oojs-ui/i18n/ku-latn.json
@@ -1,13 +1,16 @@
{
"@metadata": {
"authors": [
- "George Animal"
+ "George Animal",
+ "Bikarhêner"
]
},
+ "ooui-toolbar-more": "Bêhtir",
"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"
+ "ooui-dialog-process-continue": "Bidomîne",
+ "ooui-selectfile-placeholder": "Ti dosye nehatiye hilbijartin"
}
diff --git a/resources/lib/oojs-ui/i18n/la.json b/resources/lib/oojs-ui/i18n/la.json
new file mode 100644
index 00000000..7a9b2d23
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/la.json
@@ -0,0 +1,15 @@
+{
+ "@metadata": {
+ "authors": [
+ "Jdforrester"
+ ]
+ },
+ "ooui-toolbar-more": "Plus",
+ "ooui-toolgroup-expand": "Plus",
+ "ooui-toolgroup-collapse": "Paucior",
+ "ooui-dialog-message-accept": "Assentior",
+ "ooui-dialog-message-reject": "Dimittere",
+ "ooui-dialog-process-dismiss": "Dimittere",
+ "ooui-dialog-process-retry": "Retemptare",
+ "ooui-dialog-process-continue": "Pergere"
+}
diff --git a/resources/lib/oojs-ui/i18n/lb.json b/resources/lib/oojs-ui/i18n/lb.json
index 119d1be9..39bc6701 100644
--- a/resources/lib/oojs-ui/i18n/lb.json
+++ b/resources/lib/oojs-ui/i18n/lb.json
@@ -21,5 +21,8 @@
"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-continue": "Virufueren"
+ "ooui-dialog-process-continue": "Virufueren",
+ "ooui-selectfile-button-select": "E Fichier eraussichen",
+ "ooui-selectfile-placeholder": "Et ass kee Fichier erausgesicht",
+ "ooui-selectfile-dragdrop-placeholder": "Fichier hei ofleeën"
}
diff --git a/resources/lib/oojs-ui/i18n/li.json b/resources/lib/oojs-ui/i18n/li.json
new file mode 100644
index 00000000..f05a9571
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/li.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Pahles"
+ ]
+ },
+ "ooui-outline-control-move-down": "Item nao ónger verplaatse",
+ "ooui-outline-control-move-up": "Item nao bove verplaetse",
+ "ooui-outline-control-remove": "Item ewegsjaffe",
+ "ooui-toolbar-more": "Mieë",
+ "ooui-toolgroup-expand": "Mieë",
+ "ooui-toolgroup-collapse": "Minder",
+ "ooui-dialog-message-accept": "Ok",
+ "ooui-dialog-message-reject": "Aafbraeke",
+ "ooui-dialog-process-error": "Dao is get misgegange",
+ "ooui-dialog-process-dismiss": "Sjlete",
+ "ooui-dialog-process-retry": "Perbeer obbenuujts",
+ "ooui-dialog-process-continue": "Doorgaon",
+ "ooui-selectfile-not-supported": "Selektie van 'n besjtandj waert neet óngersteund",
+ "ooui-selectfile-placeholder": "Dao is gein besjtandj geselekteerd"
+}
diff --git a/resources/lib/oojs-ui/i18n/lt.json b/resources/lib/oojs-ui/i18n/lt.json
index ecd06a8a..fbd22d0f 100644
--- a/resources/lib/oojs-ui/i18n/lt.json
+++ b/resources/lib/oojs-ui/i18n/lt.json
@@ -3,8 +3,24 @@
"authors": [
"Audriusa",
"Eitvys200",
- "Mantak111"
+ "Mantak111",
+ "Albertas"
]
},
- "ooui-outline-control-remove": "Šalinti elementus"
+ "ooui-outline-control-move-down": "Perkelti elementą žemyn",
+ "ooui-outline-control-move-up": "Perkelti elementą aukštyn",
+ "ooui-outline-control-remove": "Šalinti elementus",
+ "ooui-toolbar-more": "Daugiau",
+ "ooui-toolgroup-expand": "Daugiau",
+ "ooui-toolgroup-collapse": "Mažiau",
+ "ooui-dialog-message-accept": "Gerai",
+ "ooui-dialog-message-reject": "Atšaukti",
+ "ooui-dialog-process-error": "Kažkas nutiko ne taip",
+ "ooui-dialog-process-dismiss": "Paslėpti",
+ "ooui-dialog-process-retry": "Bandykite dar kartą",
+ "ooui-dialog-process-continue": "Tęsti",
+ "ooui-selectfile-button-select": "Pasirinkti failą",
+ "ooui-selectfile-not-supported": "Failų pasirinkimas nepalaikomas",
+ "ooui-selectfile-placeholder": "Nėra pasirinktų failų",
+ "ooui-selectfile-dragdrop-placeholder": "Atitempkite failą čia"
}
diff --git a/resources/lib/oojs-ui/i18n/luz.json b/resources/lib/oojs-ui/i18n/luz.json
new file mode 100644
index 00000000..d48a9dfa
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/luz.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "علی ساکی لرستانی"
+ ]
+ },
+ "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": "ادامه دائن",
+ "ooui-selectfile-not-supported": "فایل انتخابی پشتیبانی نوابیه",
+ "ooui-selectfile-placeholder": "فایلی انتخاب نوابیه"
+}
diff --git a/resources/lib/oojs-ui/i18n/mk.json b/resources/lib/oojs-ui/i18n/mk.json
index 7962336c..46f37fe8 100644
--- a/resources/lib/oojs-ui/i18n/mk.json
+++ b/resources/lib/oojs-ui/i18n/mk.json
@@ -17,5 +17,9 @@
"ooui-dialog-process-error": "Нешто не е во ред",
"ooui-dialog-process-dismiss": "Тргни",
"ooui-dialog-process-retry": "Обиди се пак",
- "ooui-dialog-process-continue": "Продолжи"
+ "ooui-dialog-process-continue": "Продолжи",
+ "ooui-selectfile-button-select": "Одберете податотека",
+ "ooui-selectfile-not-supported": "Изборот на податотеки не е поддржан",
+ "ooui-selectfile-placeholder": "Немате одбрано податотека",
+ "ooui-selectfile-dragdrop-placeholder": "Тука пуштете ја податотеката"
}
diff --git a/resources/lib/oojs-ui/i18n/ml.json b/resources/lib/oojs-ui/i18n/ml.json
index 0ce0c3fd..9649b2eb 100644
--- a/resources/lib/oojs-ui/i18n/ml.json
+++ b/resources/lib/oojs-ui/i18n/ml.json
@@ -4,10 +4,24 @@
"Kavya Manohar",
"Praveenp",
"Santhosh.thottingal",
- "Vssun"
+ "Vssun",
+ "Ranjithsiji"
]
},
"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": "തുടരുക",
+ "ooui-selectfile-button-select": "പ്രമാണം തിരഞ്ഞെടുക്കുക",
+ "ooui-selectfile-not-supported": "പ്രമാണം തിരഞ്ഞെടുക്കൽ പിന്തുണയ്ക്കുന്നില്ല",
+ "ooui-selectfile-placeholder": "പ്രമാണങ്ങൾ ഒന്നും തിരഞ്ഞെടുത്തിട്ടില്ല",
+ "ooui-selectfile-dragdrop-placeholder": "പ്രമാണം ഇവിടെ ഇടുക"
}
diff --git a/resources/lib/oojs-ui/i18n/mr.json b/resources/lib/oojs-ui/i18n/mr.json
index 70061907..15a5de39 100644
--- a/resources/lib/oojs-ui/i18n/mr.json
+++ b/resources/lib/oojs-ui/i18n/mr.json
@@ -6,10 +6,17 @@
"Praju23",
"V.narsikar",
"Ydyashad",
- "संतोष दहिवळ"
+ "संतोष दहिवळ",
+ "NehalDaveND",
+ "Sau6402"
]
},
"ooui-outline-control-move-down": "घटक (आयटम) खाली सरकवा",
"ooui-outline-control-move-up": "घटक (आयटम) वर सरकवा",
- "ooui-toolbar-more": "अधिक"
+ "ooui-toolbar-more": "अधिक",
+ "ooui-toolgroup-expand": "अधिक",
+ "ooui-dialog-message-accept": "ठिक आहे",
+ "ooui-dialog-message-reject": "रद्द करा",
+ "ooui-dialog-process-dismiss": "रद्द करा",
+ "ooui-dialog-process-continue": "चालू ठेवा"
}
diff --git a/resources/lib/oojs-ui/i18n/ms.json b/resources/lib/oojs-ui/i18n/ms.json
index 823d4936..19ce1c2f 100644
--- a/resources/lib/oojs-ui/i18n/ms.json
+++ b/resources/lib/oojs-ui/i18n/ms.json
@@ -3,15 +3,22 @@
"authors": [
"Anakmalaysia",
"Aurora",
- "Pizza1016"
+ "Pizza1016",
+ "Karmadunya9-"
]
},
"ooui-outline-control-move-down": "Alihkan perkara ke bawah",
"ooui-outline-control-move-up": "Alihkan perkara ke atas",
"ooui-outline-control-remove": "Buang perkara",
"ooui-toolbar-more": "Selebihnya",
+ "ooui-toolgroup-expand": "Selengkapnya",
+ "ooui-toolgroup-collapse": "Secukupnya",
+ "ooui-dialog-message-accept": "OK",
"ooui-dialog-message-reject": "Batal",
"ooui-dialog-process-error": "Ada masalah",
"ooui-dialog-process-dismiss": "Singkir",
- "ooui-dialog-process-retry": "Cuba lagi"
+ "ooui-dialog-process-retry": "Cuba lagi",
+ "ooui-dialog-process-continue": "Teruskan",
+ "ooui-selectfile-not-supported": "Pilihan fail tidak disokong",
+ "ooui-selectfile-placeholder": "Tiada fail yang dipilih"
}
diff --git a/resources/lib/oojs-ui/i18n/nap.json b/resources/lib/oojs-ui/i18n/nap.json
index 91660373..b7e37b49 100644
--- a/resources/lib/oojs-ui/i18n/nap.json
+++ b/resources/lib/oojs-ui/i18n/nap.json
@@ -3,8 +3,25 @@
"authors": [
"Chelin",
"Chrisportelli",
- "PiRSquared17"
+ "PiRSquared17",
+ "C.R.",
+ "Candalua"
]
},
- "ooui-toolbar-more": "Atro"
+ "ooui-outline-control-move-down": "Mòve abbascio",
+ "ooui-outline-control-move-up": "Mòve ncoppa",
+ "ooui-outline-control-remove": "Leva elemento",
+ "ooui-toolbar-more": "Atro",
+ "ooui-toolgroup-expand": "Cchiù",
+ "ooui-toolgroup-collapse": "Meno",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Scancella",
+ "ooui-dialog-process-error": "Cocchosa è ghiuta malamente",
+ "ooui-dialog-process-dismiss": "Passa 'a vacca",
+ "ooui-dialog-process-retry": "Prova n'ata vota",
+ "ooui-dialog-process-continue": "Continua",
+ "ooui-selectfile-button-select": "Sceglie nu file",
+ "ooui-selectfile-not-supported": "Filtro 'e selezione nun suppurtato",
+ "ooui-selectfile-placeholder": "Nun s'è scigliuto nisciuno file",
+ "ooui-selectfile-dragdrop-placeholder": "Lassa 'o file ccà"
}
diff --git a/resources/lib/oojs-ui/i18n/nb.json b/resources/lib/oojs-ui/i18n/nb.json
index 9e773924..d3fad8dc 100644
--- a/resources/lib/oojs-ui/i18n/nb.json
+++ b/resources/lib/oojs-ui/i18n/nb.json
@@ -21,5 +21,9 @@
"ooui-dialog-process-error": "Noe gikk galt",
"ooui-dialog-process-dismiss": "Lukk",
"ooui-dialog-process-retry": "Prøv igjen",
- "ooui-dialog-process-continue": "Fortsett"
+ "ooui-dialog-process-continue": "Fortsett",
+ "ooui-selectfile-button-select": "Velg en fil",
+ "ooui-selectfile-not-supported": "Filvalg er ikke støttet",
+ "ooui-selectfile-placeholder": "Ingen fil er valgt",
+ "ooui-selectfile-dragdrop-placeholder": "Slipp fil her"
}
diff --git a/resources/lib/oojs-ui/i18n/nl.json b/resources/lib/oojs-ui/i18n/nl.json
index 7c7b1767..515eadab 100644
--- a/resources/lib/oojs-ui/i18n/nl.json
+++ b/resources/lib/oojs-ui/i18n/nl.json
@@ -31,5 +31,7 @@
"ooui-dialog-process-error": "Er is iets misgegaan",
"ooui-dialog-process-dismiss": "Sluiten",
"ooui-dialog-process-retry": "Opnieuw proberen",
- "ooui-dialog-process-continue": "Doorgaan"
+ "ooui-dialog-process-continue": "Doorgaan",
+ "ooui-selectfile-not-supported": "Selectie van een bestand wordt niet ondersteund",
+ "ooui-selectfile-placeholder": "Er is geen bestand geselecteerd"
}
diff --git a/resources/lib/oojs-ui/i18n/oc.json b/resources/lib/oojs-ui/i18n/oc.json
index 4d35b6c9..bccd615f 100644
--- a/resources/lib/oojs-ui/i18n/oc.json
+++ b/resources/lib/oojs-ui/i18n/oc.json
@@ -9,5 +9,12 @@
"ooui-outline-control-move-up": "Far montar l’element",
"ooui-outline-control-remove": "Suprimir l’element",
"ooui-toolbar-more": "Mai",
- "ooui-dialog-message-reject": "Anullar"
+ "ooui-toolgroup-expand": "Mai",
+ "ooui-toolgroup-collapse": "Mens",
+ "ooui-dialog-message-accept": "D'acòrdi",
+ "ooui-dialog-message-reject": "Anullar",
+ "ooui-dialog-process-dismiss": "Regetar",
+ "ooui-dialog-process-retry": "Ensajatz tornamai",
+ "ooui-dialog-process-continue": "Contunhar",
+ "ooui-selectfile-placeholder": "Cap de fichièr pas seleccionat"
}
diff --git a/resources/lib/oojs-ui/i18n/olo.json b/resources/lib/oojs-ui/i18n/olo.json
new file mode 100644
index 00000000..1dc994eb
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/olo.json
@@ -0,0 +1,23 @@
+{
+ "@metadata": {
+ "authors": [
+ "Mashoi7"
+ ]
+ },
+ "ooui-outline-control-move-down": "Siirrä kohteh alah",
+ "ooui-outline-control-move-up": "Siirrä kohteh yläh",
+ "ooui-outline-control-remove": "Ota kohteh iäre",
+ "ooui-toolbar-more": "Enämbi",
+ "ooui-toolgroup-expand": "Enämbi",
+ "ooui-toolgroup-collapse": "Vähembi",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Hylgiä",
+ "ooui-dialog-process-error": "Mitah haireh rodih",
+ "ooui-dialog-process-dismiss": "Hylgiä",
+ "ooui-dialog-process-retry": "Opi vie",
+ "ooui-dialog-process-continue": "Jatka",
+ "ooui-selectfile-button-select": "Valliče failu",
+ "ooui-selectfile-not-supported": "Failan valličendua ei tuveta",
+ "ooui-selectfile-placeholder": "Failua ei ole vallittu",
+ "ooui-selectfile-dragdrop-placeholder": "Kirvota failu täh"
+}
diff --git a/resources/lib/oojs-ui/i18n/om.json b/resources/lib/oojs-ui/i18n/om.json
index ecf95971..a61083b3 100644
--- a/resources/lib/oojs-ui/i18n/om.json
+++ b/resources/lib/oojs-ui/i18n/om.json
@@ -16,5 +16,7 @@
"ooui-dialog-process-error": "Dogoggorri wayii ummameera",
"ooui-dialog-process-dismiss": "Didi",
"ooui-dialog-process-retry": "Itti deebi'ii yaali",
- "ooui-dialog-process-continue": "Itti fufi"
+ "ooui-dialog-process-continue": "Itti fufi",
+ "ooui-selectfile-not-supported": "Faayilii filachuun hin danda'amu.",
+ "ooui-selectfile-placeholder": "Faayiliin wayiiyyuu hin filatamne"
}
diff --git a/resources/lib/oojs-ui/i18n/or.json b/resources/lib/oojs-ui/i18n/or.json
index dde49bf1..7d96dcb7 100644
--- a/resources/lib/oojs-ui/i18n/or.json
+++ b/resources/lib/oojs-ui/i18n/or.json
@@ -3,7 +3,8 @@
"authors": [
"Odisha1",
"Psubhashish",
- "ଶିତିକଣ୍ଠ ଦାଶ"
+ "ଶିତିକଣ୍ଠ ଦାଶ",
+ "Jnanaranjan Sahu"
]
},
"ooui-outline-control-move-down": "ବସ୍ତୁଟିକୁ ତଳକୁ ଘୁଞ୍ଚାନ୍ତୁ",
@@ -17,5 +18,7 @@
"ooui-dialog-process-error": "ଅସୁବିଧାଟିଏ ଘଟିଲା",
"ooui-dialog-process-dismiss": "ଖାରଜ",
"ooui-dialog-process-retry": "ଆଉ ଥରେ ଚେଷ୍ଟା କରନ୍ତୁ",
- "ooui-dialog-process-continue": "ଚାଲୁରଖିବେ"
+ "ooui-dialog-process-continue": "ଚାଲୁରଖିବେ",
+ "ooui-selectfile-not-supported": "ଫାଇଲ ବାଛିବା ସୁବିଧା ନାହିଁ",
+ "ooui-selectfile-placeholder": "କୌଣସି ଫାଇଲ ବଛାଯାଇନାହିଁ"
}
diff --git a/resources/lib/oojs-ui/i18n/pa.json b/resources/lib/oojs-ui/i18n/pa.json
index 8c7a1e7c..a69d76f9 100644
--- a/resources/lib/oojs-ui/i18n/pa.json
+++ b/resources/lib/oojs-ui/i18n/pa.json
@@ -10,13 +10,18 @@
},
"ooui-outline-control-move-down": "ਨੀਚੇ ਲੈਕੇ ਜਾਓ",
"ooui-outline-control-move-up": "ਉੱਤੇ ਲੈਕੇ ਜਾਓ",
+ "ooui-outline-control-remove": "ਆਈਟਮ ਹਟਾਓ",
"ooui-toolbar-more": "ਹੋਰ",
"ooui-toolgroup-expand": "ਹੋਰ",
- "ooui-toolgroup-collapse": "ਥੋੜੇ",
+ "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": "ਜਾਰੀ ਰੱਖੋ"
+ "ooui-dialog-process-continue": "ਜਾਰੀ ਰੱਖੋ",
+ "ooui-selectfile-button-select": "ਫ਼ਾਈਲ ਚੁਣੋ",
+ "ooui-selectfile-not-supported": "ਚੁਣੀ ਗਈ ਫ਼ਾਈਲ ਖੋਲੀ ਨਹੀਂ ਜਾ ਸਕਦੀ",
+ "ooui-selectfile-placeholder": "ਕੋਈ ਫ਼ਾਈਲ ਚੁਣੀ ਨਹੀਂ ਗਈ",
+ "ooui-selectfile-dragdrop-placeholder": "ਫ਼ਾਈਲ ਇੱਥੇ ਸਿੱਟੋ"
}
diff --git a/resources/lib/oojs-ui/i18n/pl.json b/resources/lib/oojs-ui/i18n/pl.json
index fbd0c8cc..9ceb96fd 100644
--- a/resources/lib/oojs-ui/i18n/pl.json
+++ b/resources/lib/oojs-ui/i18n/pl.json
@@ -16,7 +16,8 @@
"Jacenty359",
"Matik7",
"Gloria sah",
- "Andrzej aa"
+ "Andrzej aa",
+ "The Polish"
]
},
"ooui-outline-control-move-down": "Przenieś niżej",
@@ -28,7 +29,11 @@
"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-dismiss": "Powrót",
"ooui-dialog-process-retry": "Spróbuj ponownie",
- "ooui-dialog-process-continue": "Kontynuuj"
+ "ooui-dialog-process-continue": "Kontynuuj",
+ "ooui-selectfile-button-select": "Wybierz plik",
+ "ooui-selectfile-not-supported": "Wybór pliku nie jest obsługiwany",
+ "ooui-selectfile-placeholder": "Nie wybrano pliku",
+ "ooui-selectfile-dragdrop-placeholder": "Umieść plik tutaj"
}
diff --git a/resources/lib/oojs-ui/i18n/pms.json b/resources/lib/oojs-ui/i18n/pms.json
index b8fd3a58..c8b5bc7e 100644
--- a/resources/lib/oojs-ui/i18n/pms.json
+++ b/resources/lib/oojs-ui/i18n/pms.json
@@ -8,5 +8,16 @@
},
"ooui-outline-control-move-down": "Fé calé giù l'element",
"ooui-outline-control-move-up": "Fé monté l'element",
- "ooui-toolbar-more": "Ëd pi"
+ "ooui-outline-control-remove": "Gavé j'element",
+ "ooui-toolbar-more": "Ëd pi",
+ "ooui-toolgroup-expand": "Pi",
+ "ooui-toolgroup-collapse": "Men",
+ "ooui-dialog-message-accept": "Va bin",
+ "ooui-dialog-message-reject": "Scancelé",
+ "ooui-dialog-process-error": "Quaicòs a l'é andà mal",
+ "ooui-dialog-process-dismiss": "Stërmé",
+ "ooui-dialog-process-retry": "Preuva torna",
+ "ooui-dialog-process-continue": "Continua",
+ "ooui-selectfile-not-supported": "La selession d'archivi a l'é nen mantnùa",
+ "ooui-selectfile-placeholder": "Gnun archivi selessionà"
}
diff --git a/resources/lib/oojs-ui/i18n/ps.json b/resources/lib/oojs-ui/i18n/ps.json
index ebffe539..228291ac 100644
--- a/resources/lib/oojs-ui/i18n/ps.json
+++ b/resources/lib/oojs-ui/i18n/ps.json
@@ -14,5 +14,9 @@
"ooui-dialog-message-reject": "ناگارل",
"ooui-dialog-process-error": "يوه ستونزه رامنځ ته شوه",
"ooui-dialog-process-dismiss": "تړل",
- "ooui-dialog-process-retry": "بيا هڅه"
+ "ooui-dialog-process-retry": "بيا هڅه",
+ "ooui-dialog-process-continue": "پرله پورې",
+ "ooui-selectfile-button-select": "يوه دوتنه وټاکئ",
+ "ooui-selectfile-not-supported": "د دوتنې د ټاکنې ملاتړ نه دی شوی",
+ "ooui-selectfile-placeholder": "کومه دوتنه نه ده ټاکل شوې"
}
diff --git a/resources/lib/oojs-ui/i18n/pt-br.json b/resources/lib/oojs-ui/i18n/pt-br.json
index 94ea0895..bcc31e09 100644
--- a/resources/lib/oojs-ui/i18n/pt-br.json
+++ b/resources/lib/oojs-ui/i18n/pt-br.json
@@ -9,10 +9,23 @@
"Jaideraf",
"Luckas",
"OTAVIO1981",
- 555
+ 555,
+ "TheEduGobi",
+ "TheGabrielZaum"
]
},
"ooui-outline-control-move-down": "Mover item para baixo",
"ooui-outline-control-move-up": "Mover item para cima",
- "ooui-toolbar-more": "Mais"
+ "ooui-outline-control-remove": "Remover item",
+ "ooui-toolbar-more": "Mais",
+ "ooui-toolgroup-expand": "Mais",
+ "ooui-toolgroup-collapse": "Menos",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Cancelar",
+ "ooui-dialog-process-error": "Algo deu errado",
+ "ooui-dialog-process-dismiss": "Dispensar",
+ "ooui-dialog-process-retry": "Tentar novamente",
+ "ooui-dialog-process-continue": "Continuar",
+ "ooui-selectfile-not-supported": "O selecionamento de arquivos não é suportado",
+ "ooui-selectfile-placeholder": "Nenhum arquivo selecionado"
}
diff --git a/resources/lib/oojs-ui/i18n/pt.json b/resources/lib/oojs-ui/i18n/pt.json
index 7b3176fb..8d9071a7 100644
--- a/resources/lib/oojs-ui/i18n/pt.json
+++ b/resources/lib/oojs-ui/i18n/pt.json
@@ -10,7 +10,8 @@
"Jdforrester",
"Luckas",
"Vitorvicentevalente",
- "SandroHc"
+ "SandroHc",
+ "Jkb8"
]
},
"ooui-outline-control-move-down": "Mover item para baixo",
@@ -24,5 +25,8 @@
"ooui-dialog-process-error": "Algo correu mal",
"ooui-dialog-process-dismiss": "Ignorar",
"ooui-dialog-process-retry": "Tentar novamente",
- "ooui-dialog-process-continue": "Continuar"
+ "ooui-dialog-process-continue": "Continuar",
+ "ooui-selectfile-not-supported": "A seleção de ficheiros não é suportada",
+ "ooui-selectfile-placeholder": "Nenhum ficheiro selecionado",
+ "ooui-selectfile-dragdrop-placeholder": "Soltar ficheiro aqui"
}
diff --git a/resources/lib/oojs-ui/i18n/qqq.json b/resources/lib/oojs-ui/i18n/qqq.json
index c1b794ab..1a096efc 100644
--- a/resources/lib/oojs-ui/i18n/qqq.json
+++ b/resources/lib/oojs-ui/i18n/qqq.json
@@ -31,5 +31,9 @@
"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-continue": "Label for process dialog retry action button, visible when describing only warnings\n{{Identical|Continue}}"
+ "ooui-dialog-process-continue": "Label for process dialog retry action button, visible when describing only warnings\n{{Identical|Continue}}",
+ "ooui-selectfile-button-select": "Label for the file selection widget's select file button",
+ "ooui-selectfile-not-supported": "Label for the file selection widget if file selection is not supported",
+ "ooui-selectfile-placeholder": "Label for the file selection widget when no file is currently selected",
+ "ooui-selectfile-dragdrop-placeholder": "Label for the file selection widget's drop target"
}
diff --git a/resources/lib/oojs-ui/i18n/ro.json b/resources/lib/oojs-ui/i18n/ro.json
index 258f3e74..69daa180 100644
--- a/resources/lib/oojs-ui/i18n/ro.json
+++ b/resources/lib/oojs-ui/i18n/ro.json
@@ -19,5 +19,9 @@
"ooui-dialog-process-error": "Ceva nu a funcționat",
"ooui-dialog-process-dismiss": "Renunțare",
"ooui-dialog-process-retry": "Reîncearcă",
- "ooui-dialog-process-continue": "Continuă"
+ "ooui-dialog-process-continue": "Continuă",
+ "ooui-selectfile-button-select": "Alege un fișier",
+ "ooui-selectfile-not-supported": "Selecția de fișiere nu este acceptată",
+ "ooui-selectfile-placeholder": "Niciun fișier selectat",
+ "ooui-selectfile-dragdrop-placeholder": "Trageți fișierul aici"
}
diff --git a/resources/lib/oojs-ui/i18n/roa-tara.json b/resources/lib/oojs-ui/i18n/roa-tara.json
index f6f422a2..73a5a6c1 100644
--- a/resources/lib/oojs-ui/i18n/roa-tara.json
+++ b/resources/lib/oojs-ui/i18n/roa-tara.json
@@ -15,5 +15,9 @@
"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"
+ "ooui-dialog-process-continue": "Condinue",
+ "ooui-selectfile-button-select": "Scacchie 'nu file",
+ "ooui-selectfile-not-supported": "'U scacchiamende d'u file non g'è supportate",
+ "ooui-selectfile-placeholder": "Nisciune file scacchiate",
+ "ooui-selectfile-dragdrop-placeholder": "Scitte 'u file aqquà"
}
diff --git a/resources/lib/oojs-ui/i18n/ru.json b/resources/lib/oojs-ui/i18n/ru.json
index 129dd6a2..6c62d360 100644
--- a/resources/lib/oojs-ui/i18n/ru.json
+++ b/resources/lib/oojs-ui/i18n/ru.json
@@ -16,7 +16,8 @@
"Sunpriat",
"Yury Katkov",
"Умар",
- "Камалист"
+ "Камалист",
+ "Meshkov.a"
]
},
"ooui-outline-control-move-down": "Переместить элемент вниз",
@@ -30,5 +31,9 @@
"ooui-dialog-process-error": "Что-то пошло не так",
"ooui-dialog-process-dismiss": "Закрыть",
"ooui-dialog-process-retry": "Попробовать ещё раз",
- "ooui-dialog-process-continue": "Продолжить"
+ "ooui-dialog-process-continue": "Продолжить",
+ "ooui-selectfile-button-select": "Выберите файл",
+ "ooui-selectfile-not-supported": "Выбор файла не поддерживается",
+ "ooui-selectfile-placeholder": "Не выбран файл",
+ "ooui-selectfile-dragdrop-placeholder": "Перетащите файл сюда"
}
diff --git a/resources/lib/oojs-ui/i18n/sa.json b/resources/lib/oojs-ui/i18n/sa.json
new file mode 100644
index 00000000..49f038c7
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/sa.json
@@ -0,0 +1,14 @@
+{
+ "@metadata": {
+ "authors": [
+ "NehalDaveND"
+ ]
+ },
+ "ooui-outline-control-remove": "वस्तु निष्कास्यताम्",
+ "ooui-toolbar-more": "अधिकम्",
+ "ooui-toolgroup-expand": "अधिकम्",
+ "ooui-dialog-message-accept": "अस्तु",
+ "ooui-dialog-message-reject": "निरस्यताम्",
+ "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 85a94cd5..1e1b05d1 100644
--- a/resources/lib/oojs-ui/i18n/sah.json
+++ b/resources/lib/oojs-ui/i18n/sah.json
@@ -4,5 +4,19 @@
"Gazeb",
"HalanTul"
]
- }
+ },
+ "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": "Салгыы",
+ "ooui-selectfile-not-supported": "Билэни талыы өйөммөт",
+ "ooui-selectfile-placeholder": "Биир да билэ талыллыбатах"
}
diff --git a/resources/lib/oojs-ui/i18n/sco.json b/resources/lib/oojs-ui/i18n/sco.json
index 0a26a5c8..794d71f7 100644
--- a/resources/lib/oojs-ui/i18n/sco.json
+++ b/resources/lib/oojs-ui/i18n/sco.json
@@ -1,11 +1,22 @@
{
"@metadata": {
"authors": [
- "John Reid"
+ "John Reid",
+ "Foxj"
]
},
"ooui-outline-control-move-down": "Muiv eetem doon",
"ooui-outline-control-move-up": "Muiv eetem up",
"ooui-outline-control-remove": "Remuiv eetem",
- "ooui-toolbar-more": "Mair"
+ "ooui-toolbar-more": "Mair",
+ "ooui-toolgroup-expand": "Mair",
+ "ooui-toolgroup-collapse": "Less",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Cancel",
+ "ooui-dialog-process-error": "Sommit went wrang",
+ "ooui-dialog-process-dismiss": "Close",
+ "ooui-dialog-process-retry": "Hae aniter gae",
+ "ooui-dialog-process-continue": "Conteena",
+ "ooui-selectfile-not-supported": "Cannae pick ony files",
+ "ooui-selectfile-placeholder": "Nae file selectit"
}
diff --git a/resources/lib/oojs-ui/i18n/sh.json b/resources/lib/oojs-ui/i18n/sh.json
index b40fa04e..db6fa3c4 100644
--- a/resources/lib/oojs-ui/i18n/sh.json
+++ b/resources/lib/oojs-ui/i18n/sh.json
@@ -5,5 +5,17 @@
]
},
"ooui-outline-control-move-down": "Pomakni stavku dolje",
- "ooui-outline-control-move-up": "Pomakni stavku gore"
+ "ooui-outline-control-move-up": "Premjesti stavku gore",
+ "ooui-outline-control-remove": "Ukloni stavku",
+ "ooui-toolbar-more": "Više",
+ "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",
+ "ooui-selectfile-not-supported": "Izbor datoteke nije podržan",
+ "ooui-selectfile-placeholder": "Nijedna datoteka nije odabrana"
}
diff --git a/resources/lib/oojs-ui/i18n/sk.json b/resources/lib/oojs-ui/i18n/sk.json
index c8246da9..fa658889 100644
--- a/resources/lib/oojs-ui/i18n/sk.json
+++ b/resources/lib/oojs-ui/i18n/sk.json
@@ -2,11 +2,21 @@
"@metadata": {
"authors": [
"Mimarik",
- "Teslaton"
+ "Teslaton",
+ "Kusavica"
]
},
"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"
+ "ooui-toolbar-more": "Viac",
+ "ooui-toolgroup-expand": "Viac",
+ "ooui-toolgroup-collapse": "Menej",
+ "ooui-dialog-message-accept": "OK",
+ "ooui-dialog-message-reject": "Zrušiť",
+ "ooui-dialog-process-error": "Niečo sa pokazilo",
+ "ooui-dialog-process-dismiss": "Zrušiť",
+ "ooui-dialog-process-retry": "Skúsiť znova",
+ "ooui-dialog-process-continue": "Pokračovať",
+ "ooui-selectfile-placeholder": "Nie je vybraný žiadny súbor"
}
diff --git a/resources/lib/oojs-ui/i18n/sl.json b/resources/lib/oojs-ui/i18n/sl.json
index a40728ad..e113671c 100644
--- a/resources/lib/oojs-ui/i18n/sl.json
+++ b/resources/lib/oojs-ui/i18n/sl.json
@@ -18,5 +18,7 @@
"ooui-dialog-process-error": "Nekaj je šlo narobe",
"ooui-dialog-process-dismiss": "Skrij",
"ooui-dialog-process-retry": "Poskusi znova",
- "ooui-dialog-process-continue": "Nadaljuj"
+ "ooui-dialog-process-continue": "Nadaljuj",
+ "ooui-selectfile-not-supported": "Izbira datoteke ni podprta",
+ "ooui-selectfile-placeholder": "Nobena datoteka ni izbrana"
}
diff --git a/resources/lib/oojs-ui/i18n/sq.json b/resources/lib/oojs-ui/i18n/sq.json
index ec180199..4bf5dac9 100644
--- a/resources/lib/oojs-ui/i18n/sq.json
+++ b/resources/lib/oojs-ui/i18n/sq.json
@@ -5,15 +5,22 @@
"Kushtrim",
"Elioqoshi",
"GretaDoci",
- "Gertakapllani"
+ "Gertakapllani",
+ "Techlik"
]
},
"ooui-outline-control-move-down": "Zhvendose artikullin më poshtë",
"ooui-outline-control-move-up": "Zhvendose artikullin më lart",
"ooui-outline-control-remove": "Hiq artikullin",
"ooui-toolbar-more": "Më tepër...",
+ "ooui-toolgroup-expand": "Më tepër...",
+ "ooui-toolgroup-collapse": "Më pak",
"ooui-dialog-message-accept": "Në rregull",
"ooui-dialog-message-reject": "Anullo",
"ooui-dialog-process-error": "Diçka shkoi keq",
- "ooui-dialog-process-retry": "Provo përsëri"
+ "ooui-dialog-process-dismiss": "Largoje",
+ "ooui-dialog-process-retry": "Provo përsëri",
+ "ooui-dialog-process-continue": "Vazhdo",
+ "ooui-selectfile-not-supported": "Skedari i përzgjedhur nuk përkrahet",
+ "ooui-selectfile-placeholder": "Nuk është zgjedhur asnjë skedar"
}
diff --git a/resources/lib/oojs-ui/i18n/sr-ec.json b/resources/lib/oojs-ui/i18n/sr-ec.json
index c827554e..de52812e 100644
--- a/resources/lib/oojs-ui/i18n/sr-ec.json
+++ b/resources/lib/oojs-ui/i18n/sr-ec.json
@@ -17,5 +17,7 @@
"ooui-dialog-process-error": "Нешто је пошло наопако",
"ooui-dialog-process-dismiss": "Одбаци",
"ooui-dialog-process-retry": "Покушај поново",
- "ooui-dialog-process-continue": "Настави"
+ "ooui-dialog-process-continue": "Настави",
+ "ooui-selectfile-button-select": "Изабери датотеку",
+ "ooui-selectfile-placeholder": "Није изабрана ниједна датотека"
}
diff --git a/resources/lib/oojs-ui/i18n/su.json b/resources/lib/oojs-ui/i18n/su.json
new file mode 100644
index 00000000..a8cf762e
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/su.json
@@ -0,0 +1,21 @@
+{
+ "@metadata": {
+ "authors": [
+ "Kandar"
+ ]
+ },
+ "ooui-outline-control-move-down": "Pindahkeun ka handap",
+ "ooui-outline-control-move-up": "Pindahkeun ka luhur",
+ "ooui-outline-control-remove": "Hapus",
+ "ooui-toolbar-more": "Lobaan",
+ "ooui-toolgroup-expand": "Lobaan",
+ "ooui-toolgroup-collapse": "Saeutikan",
+ "ooui-dialog-message-accept": "Heug",
+ "ooui-dialog-message-reject": "Bolay",
+ "ooui-dialog-process-error": "Aya nu teu bener",
+ "ooui-dialog-process-dismiss": "Tutup",
+ "ooui-dialog-process-retry": "Cobaan deui",
+ "ooui-dialog-process-continue": "Teruskeun",
+ "ooui-selectfile-not-supported": "Pamilihan berkas teu dirojong",
+ "ooui-selectfile-placeholder": "Taya berkas anu dipilih"
+}
diff --git a/resources/lib/oojs-ui/i18n/sv.json b/resources/lib/oojs-ui/i18n/sv.json
index d499427c..3ffbc489 100644
--- a/resources/lib/oojs-ui/i18n/sv.json
+++ b/resources/lib/oojs-ui/i18n/sv.json
@@ -11,7 +11,8 @@
"Sendelbach",
"Skalman",
"WikiPhoenix",
- "Lokal Profil"
+ "Lokal Profil",
+ "Warrakkk"
]
},
"ooui-outline-control-move-down": "Flytta ned objekt",
@@ -25,5 +26,9 @@
"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-continue": "Fortsätt"
+ "ooui-dialog-process-continue": "Fortsätt",
+ "ooui-selectfile-button-select": "Välj en fil",
+ "ooui-selectfile-not-supported": "Filval stöds inte",
+ "ooui-selectfile-placeholder": "Ingen fil är vald",
+ "ooui-selectfile-dragdrop-placeholder": "Släpp filen här"
}
diff --git a/resources/lib/oojs-ui/i18n/ta.json b/resources/lib/oojs-ui/i18n/ta.json
index 122d4a27..6e7b2494 100644
--- a/resources/lib/oojs-ui/i18n/ta.json
+++ b/resources/lib/oojs-ui/i18n/ta.json
@@ -5,9 +5,22 @@
"Sank",
"Shanmugamp7",
"மதனாஹரன்",
- "ElangoRamanujam"
+ "ElangoRamanujam",
+ "Info-farmer"
]
},
+ "ooui-outline-control-move-down": "உருப்படியை கீழிடு",
+ "ooui-outline-control-move-up": "உருப்படியை மேலிடு",
+ "ooui-outline-control-remove": "உருப்படியை நீக்கு",
+ "ooui-toolbar-more": "மேலும்",
"ooui-toolgroup-expand": "மேலும்",
- "ooui-dialog-process-continue": "தொடரவும்"
+ "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": "தொடரவும்",
+ "ooui-selectfile-not-supported": "கோப்புத்தேர்வு ஆதரவாக இல்லை",
+ "ooui-selectfile-placeholder": "எக்கோப்பும் தெரிவாகவில்லை"
}
diff --git a/resources/lib/oojs-ui/i18n/te.json b/resources/lib/oojs-ui/i18n/te.json
index d4868706..957b0d0f 100644
--- a/resources/lib/oojs-ui/i18n/te.json
+++ b/resources/lib/oojs-ui/i18n/te.json
@@ -9,5 +9,14 @@
"Visdaviva",
"மதனாஹரன்"
]
- }
+ },
+ "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/tl.json b/resources/lib/oojs-ui/i18n/tl.json
index b3a9f246..c0dbd5fd 100644
--- a/resources/lib/oojs-ui/i18n/tl.json
+++ b/resources/lib/oojs-ui/i18n/tl.json
@@ -2,13 +2,22 @@
"@metadata": {
"authors": [
"AnakngAraw",
- "Sky Harbor"
+ "Sky Harbor",
+ "Jewel457"
]
},
"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-toolgroup-expand": "Maraming iba pa",
+ "ooui-toolgroup-collapse": "Kakaunti",
"ooui-dialog-message-accept": "Sige",
- "ooui-dialog-message-reject": "Huwag ituloy"
+ "ooui-dialog-message-reject": "Huwag ituloy",
+ "ooui-dialog-process-error": "May pagkakamali",
+ "ooui-dialog-process-dismiss": "Isa-isantabi",
+ "ooui-dialog-process-retry": "Subuking muli",
+ "ooui-dialog-process-continue": "Magpatuloy",
+ "ooui-selectfile-not-supported": "Ang pagpili ng file ay hindi kinakatigan",
+ "ooui-selectfile-placeholder": "Walang piniling file"
}
diff --git a/resources/lib/oojs-ui/i18n/uk.json b/resources/lib/oojs-ui/i18n/uk.json
index 0197a4ce..a38afbfd 100644
--- a/resources/lib/oojs-ui/i18n/uk.json
+++ b/resources/lib/oojs-ui/i18n/uk.json
@@ -15,7 +15,9 @@
"Tel'et",
"Tifinaghes",
"Ата",
- "Piramidion"
+ "Piramidion",
+ "A1",
+ "Dars"
]
},
"ooui-outline-control-move-down": "Перемістити елемент униз",
@@ -29,5 +31,9 @@
"ooui-dialog-process-error": "Щось пішло не так",
"ooui-dialog-process-dismiss": "Приховати",
"ooui-dialog-process-retry": "Спробуйте ще раз",
- "ooui-dialog-process-continue": "Продовжити"
+ "ooui-dialog-process-continue": "Продовжити",
+ "ooui-selectfile-button-select": "Оберіть файл",
+ "ooui-selectfile-not-supported": "Вибір файлу не підтримується",
+ "ooui-selectfile-placeholder": "Жодного файлу не вибрано",
+ "ooui-selectfile-dragdrop-placeholder": "Помістіть файл сюди"
}
diff --git a/resources/lib/oojs-ui/i18n/vec.json b/resources/lib/oojs-ui/i18n/vec.json
index 4de584bf..ddd27c5e 100644
--- a/resources/lib/oojs-ui/i18n/vec.json
+++ b/resources/lib/oojs-ui/i18n/vec.json
@@ -9,5 +9,14 @@
"ooui-outline-control-move-down": "Sposta in baso",
"ooui-outline-control-move-up": "Sposta in sima",
"ooui-toolbar-more": "Altro",
- "ooui-dialog-message-accept": "Va ben"
+ "ooui-toolgroup-expand": "Piassè",
+ "ooui-toolgroup-collapse": "Manco",
+ "ooui-dialog-message-accept": "Va ben",
+ "ooui-dialog-message-reject": "Fa gnente",
+ "ooui-dialog-process-error": "Xe 'ndà storto calcossa",
+ "ooui-dialog-process-dismiss": "Scondi",
+ "ooui-dialog-process-retry": "Proa da novo",
+ "ooui-dialog-process-continue": "Và vanti",
+ "ooui-selectfile-button-select": "Siegli un file",
+ "ooui-selectfile-dragdrop-placeholder": "Mola zo el file chì rento"
}
diff --git a/resources/lib/oojs-ui/i18n/vi.json b/resources/lib/oojs-ui/i18n/vi.json
index d5c1e364..fd630814 100644
--- a/resources/lib/oojs-ui/i18n/vi.json
+++ b/resources/lib/oojs-ui/i18n/vi.json
@@ -4,19 +4,24 @@
"Cheers!",
"Jdforrester",
"Minh Nguyen",
- "Max20091"
+ "Max20091",
+ "Anh88"
]
},
"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-outline-control-remove": "Xóa mục",
"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-error": "Có thứ gì đó bị lỗi",
"ooui-dialog-process-dismiss": "Bỏ qua",
"ooui-dialog-process-retry": "Thử lại",
- "ooui-dialog-process-continue": "Tiếp tục"
+ "ooui-dialog-process-continue": "Tiếp tục",
+ "ooui-selectfile-button-select": "Chọn tập tin",
+ "ooui-selectfile-not-supported": "Không hỗ trợ việc chọn tập tin",
+ "ooui-selectfile-placeholder": "Không có tập tin nào được chọn",
+ "ooui-selectfile-dragdrop-placeholder": "Thả tập tin vào đây"
}
diff --git a/resources/lib/oojs-ui/i18n/xmf.json b/resources/lib/oojs-ui/i18n/xmf.json
new file mode 100644
index 00000000..f5bfa2c6
--- /dev/null
+++ b/resources/lib/oojs-ui/i18n/xmf.json
@@ -0,0 +1,19 @@
+{
+ "@metadata": {
+ "authors": [
+ "David1010"
+ ]
+ },
+ "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/yi.json b/resources/lib/oojs-ui/i18n/yi.json
index a850fce2..f206a723 100644
--- a/resources/lib/oojs-ui/i18n/yi.json
+++ b/resources/lib/oojs-ui/i18n/yi.json
@@ -10,9 +10,14 @@
"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": "פֿארזעצן",
+ "ooui-selectfile-not-supported": "טעקע אויסווייל נישט געשטיצט",
+ "ooui-selectfile-placeholder": "קיין טעקע נישט אויסגעוויילט"
}
diff --git a/resources/lib/oojs-ui/i18n/yue.json b/resources/lib/oojs-ui/i18n/yue.json
index 81ad9a95..629528de 100644
--- a/resources/lib/oojs-ui/i18n/yue.json
+++ b/resources/lib/oojs-ui/i18n/yue.json
@@ -1,16 +1,26 @@
{
"@metadata": {
"authors": [
- "Deryck Chan"
+ "Deryck Chan",
+ "William915",
+ "Shinjiman",
+ "Ktchankt"
]
},
"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-retry": "再試過",
+ "ooui-dialog-process-continue": "繼續",
+ "ooui-selectfile-button-select": "揀檔案",
+ "ooui-selectfile-not-supported": "未有文件選擇功能",
+ "ooui-selectfile-placeholder": "無揀到文件",
+ "ooui-selectfile-dragdrop-placeholder": "放檔案響度"
}
diff --git a/resources/lib/oojs-ui/i18n/zh-hans.json b/resources/lib/oojs-ui/i18n/zh-hans.json
index ed2f61e4..9934d9d0 100644
--- a/resources/lib/oojs-ui/i18n/zh-hans.json
+++ b/resources/lib/oojs-ui/i18n/zh-hans.json
@@ -16,19 +16,24 @@
"Yfdyh000",
"Zhangjintao",
"乌拉跨氪",
- "Great Brightstar"
+ "Great Brightstar",
+ "Nbdd0121"
]
},
- "ooui-outline-control-move-down": "项目下移",
- "ooui-outline-control-move-up": "项目上移",
+ "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-error": "发生了一些错误",
+ "ooui-dialog-process-dismiss": "关闭",
"ooui-dialog-process-retry": "重试",
- "ooui-dialog-process-continue": "继续"
+ "ooui-dialog-process-continue": "继续",
+ "ooui-selectfile-button-select": "选择一个文件",
+ "ooui-selectfile-not-supported": "文件选择不受支持",
+ "ooui-selectfile-placeholder": "没有选定文件",
+ "ooui-selectfile-dragdrop-placeholder": "将文件拖动至此"
}
diff --git a/resources/lib/oojs-ui/i18n/zh-hant.json b/resources/lib/oojs-ui/i18n/zh-hant.json
index 3fd8d361..f70efe19 100644
--- a/resources/lib/oojs-ui/i18n/zh-hant.json
+++ b/resources/lib/oojs-ui/i18n/zh-hant.json
@@ -14,7 +14,8 @@
"Spring Roll Conan",
"Waihorace",
"Cwlin0416",
- "LNDDYL"
+ "LNDDYL",
+ "Shangkuanlc"
]
},
"ooui-outline-control-move-down": "項目下移",
@@ -28,5 +29,9 @@
"ooui-dialog-process-error": "發生不明錯誤",
"ooui-dialog-process-dismiss": "關閉",
"ooui-dialog-process-retry": "再試一次",
- "ooui-dialog-process-continue": "繼續"
+ "ooui-dialog-process-continue": "繼續",
+ "ooui-selectfile-button-select": "選擇一個檔案",
+ "ooui-selectfile-not-supported": "無法支援所選擇的檔案",
+ "ooui-selectfile-placeholder": "未選擇檔案",
+ "ooui-selectfile-dragdrop-placeholder": "拖曳檔案到此處"
}
diff --git a/resources/lib/oojs-ui/oojs-ui-apex-noimages.css b/resources/lib/oojs-ui/oojs-ui-apex-noimages.css
new file mode 100644
index 00000000..50129348
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-apex-noimages.css
@@ -0,0 +1,2956 @@
+/*!
+ * OOjs UI v0.12.12
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs UI Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-10-13T20:38:26Z
+ */
+@-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;
+}
+.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 {
+ color: #333333;
+}
+.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 > .oo-ui-iconElement-icon {
+ /* Don't animate opacities for now, causes wiggling in Chrome (bug 63020) */
+ /*.oo-ui-transition(opacity @medium-ease);*/
+}
+.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-frameless > .oo-ui-buttonElement-button:focus {
+ outline: none;
+}
+.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;
+}
+.oo-ui-buttonElement-frameless.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ margin-left: 0.25em;
+}
+.oo-ui-buttonElement-frameless > input.oo-ui-buttonElement-button {
+ padding-left: 0.25em;
+ color: #333333;
+}
+.oo-ui-buttonElement-frameless > input.oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-frameless > input.oo-ui-buttonElement-button:focus {
+ color: #000000;
+}
+.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-progressive > .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;
+ -moz-transition: border-color 100ms ease;
+ -ms-transition: border-color 100ms ease;
+ -o-transition: border-color 100ms ease;
+ transition: border-color 100ms ease;
+ 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: -o-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+ background-image: linear-gradient(to bottom, #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;
+ 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-widget-enabled > .oo-ui-buttonElement-button:active,
+.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: -o-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+ background-image: linear-gradient(to bottom, #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-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-flaggedElement-progressive > .oo-ui-buttonElement-button {
+ border: 1px solid #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: -o-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
+ background-image: linear-gradient(to bottom, #eaf4fa 0%, #b0d9ee 100%);
+}
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:hover,
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button:focus {
+ border-color: #9dc2d4;
+}
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive.oo-ui-widget-enabled > .oo-ui-buttonElement-button:active,
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive.oo-ui-buttonElement-active > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-progressive.oo-ui-buttonElement-pressed > .oo-ui-buttonElement-button {
+ border: 1px solid #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: -o-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+ background-image: linear-gradient(to bottom, #b0d9ee 0%, #eaf4fa 100%);
+}
+.oo-ui-buttonElement-framed.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button {
+ border: 1px solid #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: -o-linear-gradient(top, #f0fbe1 0%, #c3e59a 100%);
+ background-image: linear-gradient(to bottom, #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-widget-enabled > .oo-ui-buttonElement-button:active,
+.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: 1px solid #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: -o-linear-gradient(top, #c3e59a 0%, #f0fbe1 100%);
+ background-image: linear-gradient(to bottom, #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;
+ -webkit-transform: translate3d(0, 0, 0);
+ 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-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;
+ background-repeat: no-repeat;
+}
+.oo-ui-iconElement .oo-ui-iconElement-icon,
+.oo-ui-iconElement.oo-ui-iconElement-icon {
+ opacity: 0.8;
+}
+.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator,
+.oo-ui-indicatorElement.oo-ui-indicatorElement-indicator {
+ background-size: contain;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator,
+.oo-ui-indicatorElement.oo-ui-indicatorElement-indicator {
+ opacity: 0.8;
+}
+.oo-ui-lookupElement > .oo-ui-menuSelectWidget {
+ z-index: 1;
+ width: 100%;
+}
+.oo-ui-pendingElement-pending {
+ background-image: /* @embed */ url(themes/apex/images/textures/pending.gif);
+}
+.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;
+}
+.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-fieldLayout-body > .oo-ui-labelElement-label {
+ color: #cccccc;
+}
+.oo-ui-fieldLayout-messages {
+ list-style: none none;
+ margin: 0;
+ padding: 0;
+ margin-top: 0.25em;
+ margin-left: 0.25em;
+}
+.oo-ui-fieldLayout-messages > li {
+ margin: 0;
+ padding: 0;
+}
+.oo-ui-fieldLayout-messages .oo-ui-iconWidget {
+ display: none;
+}
+.oo-ui-fieldLayout-messages .oo-ui-fieldLayout-messages-error {
+ color: #d45353;
+}
+.oo-ui-fieldLayout-messages .oo-ui-labelWidget {
+ padding: 0;
+ line-height: 1.875em;
+ vertical-align: middle;
+}
+.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;
+}
+.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 200ms ease;
+ -moz-transition: all 200ms ease;
+ -ms-transition: all 200ms ease;
+ -o-transition: all 200ms ease;
+ transition: all 200ms ease;
+}
+.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-radius: 0.5em;
+ box-shadow: 0 0.25em 1em rgba(0, 0, 0, 0.25);
+}
+.oo-ui-panelLayout-padded.oo-ui-panelLayout-framed {
+ margin: 1em 0;
+}
+.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
+ display: block;
+ position: relative;
+}
+.oo-ui-horizontalLayout > .oo-ui-widget {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-horizontalLayout > .oo-ui-layout {
+ display: inline-block;
+}
+.oo-ui-horizontalLayout > .oo-ui-widget {
+ margin-right: 0.5em;
+}
+.oo-ui-horizontalLayout > .oo-ui-widget:last-child {
+ margin-right: 0;
+}
+.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:first-child > .oo-ui-popupToolGroup {
+ border-top-left-radius: 0.3125em;
+ border-bottom-left-radius: 0.3125em;
+}
+.oo-ui-toolGroupTool:last-child > .oo-ui-popupToolGroup {
+ border-top-right-radius: 0.3125em;
+ border-bottom-right-radius: 0.3125em;
+}
+.oo-ui-toolGroupTool > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle {
+ height: 1.875em;
+ padding: 0.3125em;
+}
+.oo-ui-toolGroupTool > .oo-ui-popupToolGroup > .oo-ui-popupToolGroup-handle .oo-ui-iconElement-icon {
+ height: 1.875em;
+ 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;
+ margin: 0.375em;
+ border-radius: 0.3125em;
+ border: 1px solid transparent;
+ -webkit-transition: border-color 250ms ease;
+ -moz-transition: border-color 250ms ease;
+ -ms-transition: border-color 250ms ease;
+ -o-transition: border-color 250ms ease;
+ transition: border-color 250ms ease;
+}
+.oo-ui-toolGroup-empty {
+ display: none;
+}
+.oo-ui-toolGroup .oo-ui-tool-link {
+ text-decoration: none;
+}
+.oo-ui-toolbar-narrow .oo-ui-toolGroup + .oo-ui-toolGroup {
+ margin-left: 0;
+}
+.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-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 {
+ outline: 0;
+ cursor: default;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool {
+ margin: -1px 0 -1px -1px;
+ border: 1px solid transparent;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool:first-child {
+ border-top-left-radius: 0.3125em;
+ border-bottom-left-radius: 0.3125em;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool:last-child {
+ margin-right: -1px;
+ border-top-right-radius: 0.3125em;
+ border-bottom-right-radius: 0.3125em;
+}
+.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
+ height: 1.875em;
+ padding: 0.3125em;
+}
+.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;
+}
+.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);
+}
+.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.0875em 0.0875em 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: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+ background-image: linear-gradient(to bottom, #f1f7fb 0%, #ffffff 100%);
+}
+.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:focus {
+ outline: 0;
+}
+.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:hover > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 1;
+}
+.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool:focus {
+ outline: 0;
+}
+.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link:focus {
+ outline: 0;
+}
+.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-tool-title {
+ color: #cccccc;
+}
+.oo-ui-barToolGroup.oo-ui-widget-disabled > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link .oo-ui-iconElement-icon {
+ opacity: 0.2;
+}
+.oo-ui-popupToolGroup {
+ position: relative;
+ height: 2.5em;
+ 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;
+}
+.oo-ui-popupToolGroup.oo-ui-widget-disabled .oo-ui-popupToolGroup-handle {
+ outline: 0;
+ cursor: default;
+}
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
+ display: none;
+ position: absolute;
+ z-index: 4;
+}
+.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: 2.25em;
+}
+.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-handle .oo-ui-indicatorElement-indicator {
+ width: 0.9375em;
+ height: 0.9375em;
+ margin: 0.78125em;
+ top: 0;
+ right: 0;
+}
+.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: 1.875em;
+ margin: 0.3125em;
+ top: 0;
+ left: 0.3125em;
+}
+.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.0875em 0.0875em 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: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+ background-image: linear-gradient(to bottom, #f1f7fb 0%, #ffffff 100%);
+}
+.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
+ top: 2.5em;
+ margin: 0 -1px;
+ border: 1px solid #cccccc;
+ background-color: white;
+ box-shadow: 0 0.3125em 1.25em rgba(0, 0, 0, 0.25);
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link {
+ padding: 0.3125em 0 0.3125em 0.3125em;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-iconElement-icon {
+ height: 1.875em;
+ width: 1.875em;
+ min-width: 1.875em;
+}
+.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
+ padding-left: 0.5em;
+}
+.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-toolGroup-tools {
+ padding: 0.3125em;
+}
+.oo-ui-listToolGroup.oo-ui-popupToolGroup-active {
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.oo-ui-listToolGroup .oo-ui-tool {
+ border: 1px solid transparent;
+ margin: -1px 0;
+ padding: 0 0.625em 0 0;
+}
+.oo-ui-listToolGroup .oo-ui-tool-active.oo-ui-widget-enabled {
+ border-color: rgba(0, 0, 0, 0.1);
+ box-shadow: inset 0 0.0875em 0.0875em 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: -o-linear-gradient(top, #f1f7fb 0%, #ffffff 100%);
+ background-image: linear-gradient(to bottom, #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: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-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 {
+ border-color: rgba(0, 0, 0, 0.1);
+}
+.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-toolGroup-tools {
+ padding: 0.3125em 0 0.3125em 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 {
+ padding: 0 1.25em 0 0.3125em;
+}
+.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/apex/images/icons/check.png");
+ background-image: -webkit-linear-gradient(transparent, transparent), /* @embed */ url("themes/apex/images/icons/check.svg");
+ background-image: linear-gradient(transparent, transparent), /* @embed */ url("themes/apex/images/icons/check.svg");
+ background-image: -o-linear-gradient(transparent, transparent), url("themes/apex/images/icons/check.png");
+}
+.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;
+ 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: #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: -o-linear-gradient(top, #ffffff 0%, #f1f7fb 100%);
+ background-image: linear-gradient(to bottom, #ffffff 0%, #f1f7fb 100%);
+}
+.oo-ui-toolbar-bar .oo-ui-toolbar-bar {
+ border: none;
+ background: none;
+}
+.oo-ui-toolbar-actions > .oo-ui-buttonElement-framed,
+.oo-ui-toolbar-actions > .oo-ui-buttonElement-framed:last-child {
+ margin-top: 0.4em;
+ margin-bottom: 0.4em;
+ margin-right: 0.5em;
+}
+.oo-ui-toolbar-actions > .oo-ui-buttonElement-frameless.oo-ui-labelElement,
+.oo-ui-toolbar-actions > .oo-ui-buttonElement-frameless:last-child.oo-ui-labelElement {
+ margin: 0;
+}
+.oo-ui-toolbar-actions > .oo-ui-buttonElement-frameless.oo-ui-labelElement > .oo-ui-buttonElement-button,
+.oo-ui-toolbar-actions > .oo-ui-buttonElement-frameless:last-child.oo-ui-labelElement > .oo-ui-buttonElement-button {
+ margin: 0;
+ padding: 0 0.3125em;
+}
+.oo-ui-toolbar-actions > .oo-ui-buttonElement-frameless.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label,
+.oo-ui-toolbar-actions > .oo-ui-buttonElement-frameless:last-child.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ margin: 0 1em;
+ line-height: 3.40625em;
+ /* 43/12.8 */
+}
+.oo-ui-toolbar-shadow {
+ background-image: /* @embed */ url(themes/apex/images/toolbar-shadow.png);
+ bottom: -9px;
+ height: 9px;
+ opacity: 0.5;
+ -webkit-transition: opacity 500ms ease;
+ -moz-transition: opacity 500ms ease;
+ -ms-transition: opacity 500ms ease;
+ -o-transition: opacity 500ms ease;
+ transition: opacity 500ms ease;
+}
+.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: #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,
+.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: #a7dcff;
+}
+.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;
+}
+.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: 0.3em;
+ 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: 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-radioSelectWidget {
+ padding: 0.75em 0 0.5em 0;
+}
+.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-radioOptionWidget {
+ cursor: default;
+ padding: 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-left: 0.5em;
+}
+.oo-ui-radioOptionWidget .oo-ui-radioInputWidget {
+ margin-right: 0;
+}
+.oo-ui-labelWidget {
+ display: inline-block;
+ padding: 0.5em 0;
+}
+.oo-ui-iconWidget {
+ display: inline-block;
+ vertical-align: middle;
+ 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;
+ 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: 0.3em;
+ 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: 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-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;
+ box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #dddddd;
+ border: 1px solid #cccccc;
+ margin-right: 0.5em;
+ 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: -o-linear-gradient(top, #dddddd 0%, #ffffff 100%);
+ background-image: linear-gradient(to bottom, #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:last-child {
+ margin-right: 0;
+}
+.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 250ms ease, margin-left 250ms ease;
+ -moz-transition: left 250ms ease, margin-left 250ms ease;
+ -ms-transition: left 250ms ease, margin-left 250ms ease;
+ -o-transition: left 250ms ease, margin-left 250ms ease;
+ transition: left 250ms ease, margin-left 250ms ease;
+ 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: -o-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+ background-image: linear-gradient(to bottom, #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 250ms ease;
+ -moz-transition: opacity 250ms ease;
+ -ms-transition: opacity 250ms ease;
+ -o-transition: opacity 250ms ease;
+ transition: opacity 250ms ease;
+ 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: -o-linear-gradient(top, #b0d9ee 0%, #eaf4fa 100%);
+ background-image: linear-gradient(to bottom, #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-progressBarWidget {
+ max-width: 50em;
+ border: 1px solid #cccccc;
+ border-radius: 0.25em;
+ overflow: hidden;
+}
+.oo-ui-progressBarWidget-bar {
+ height: 1em;
+ border-right: 1px solid #cccccc;
+ -webkit-transition: width 250ms ease, margin-left 250ms ease;
+ -moz-transition: width 250ms ease, margin-left 250ms ease;
+ -ms-transition: width 250ms ease, margin-left 250ms ease;
+ -o-transition: width 250ms ease, margin-left 250ms ease;
+ transition: width 250ms ease, margin-left 250ms ease;
+ 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: -o-linear-gradient(top, #eaf4fa 0%, #b0d9ee 100%);
+ background-image: linear-gradient(to bottom, #eaf4fa 0%, #b0d9ee 100%);
+}
+.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: 1px solid #a6cee1;
+}
+.oo-ui-progressBarWidget.oo-ui-widget-disabled {
+ opacity: 0.6;
+}
+.oo-ui-actionWidget.oo-ui-pendingElement-pending {
+ background-image: /* @embed */ url(themes/apex/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 #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: 6px;
+}
+.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: -7px;
+ left: -6px;
+ border-bottom-color: #aaaaaa;
+ border-width: 7px;
+}
+.oo-ui-popupWidget-anchored .oo-ui-popupWidget-anchor:after {
+ bottom: -7px;
+ left: -5px;
+ border-bottom-color: #ffffff;
+ border-width: 6px;
+}
+.oo-ui-popupWidget-transitioning .oo-ui-popupWidget-popup {
+ -webkit-transition: width 100ms ease, height 100ms ease, left 100ms ease;
+ -moz-transition: width 100ms ease, height 100ms ease, left 100ms ease;
+ -ms-transition: width 100ms ease, height 100ms ease, left 100ms ease;
+ -o-transition: width 100ms ease, height 100ms ease, left 100ms ease;
+ transition: width 100ms ease, height 100ms ease, left 100ms ease;
+}
+.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.25em;
+}
+.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-buttonInputWidget > button,
+.oo-ui-buttonInputWidget > input {
+ border: 0;
+ padding: 0;
+ background-color: transparent;
+}
+.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 {
+ background: #ffffff;
+ height: 2.5em;
+ padding: 0.5em;
+ font-size: inherit;
+ font-family: inherit;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ border-radius: 0.25em;
+}
+.oo-ui-dropdownInputWidget.oo-ui-widget-enabled select:hover,
+.oo-ui-dropdownInputWidget.oo-ui-widget-enabled select:focus {
+ border-color: rgba(0, 0, 0, 0.2);
+ outline: none;
+}
+.oo-ui-dropdownInputWidget.oo-ui-widget-disabled select {
+ color: #cccccc;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.oo-ui-radioSelectInputWidget .oo-ui-fieldLayout {
+ margin-bottom: 0;
+}
+.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 input[type="search"] {
+ -webkit-appearance: none;
+}
+.oo-ui-textInputWidget input[type="search"]::-ms-clear {
+ display: none;
+}
+.oo-ui-textInputWidget input[type="search"]::-ms-reveal {
+ display: none;
+}
+.oo-ui-textInputWidget input[type="search"]::-webkit-search-decoration,
+.oo-ui-textInputWidget input[type="search"]::-webkit-search-cancel-button,
+.oo-ui-textInputWidget input[type="search"]::-webkit-search-results-button,
+.oo-ui-textInputWidget input[type="search"]::-webkit-search-results-decoration {
+ display: none;
+}
+.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%;
+ -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: text;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-textInputWidget-type-search > .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;
+ line-height: 1.275em;
+ font-size: inherit;
+ font-family: inherit;
+ background-color: #ffffff;
+ color: black;
+ border: 1px solid #cccccc;
+ box-shadow: 0 0 0 white, inset 0 0.1em 0.2em #dddddd;
+ border-radius: 0.25em;
+ -webkit-transition: border-color 250ms ease, box-shadow 250ms ease;
+ -moz-transition: border-color 250ms ease, box-shadow 250ms ease;
+ -ms-transition: border-color 250ms ease, box-shadow 250ms ease;
+ -o-transition: border-color 250ms ease, box-shadow 250ms ease;
+ transition: border-color 250ms ease, box-shadow 250ms ease;
+}
+.oo-ui-textInputWidget input.oo-ui-pendingElement-pending,
+.oo-ui-textInputWidget textarea.oo-ui-pendingElement-pending {
+ background-color: transparent;
+}
+.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.oo-ui-widget-enabled input[readonly],
+.oo-ui-textInputWidget.oo-ui-widget-enabled textarea[readonly] {
+ color: #777777;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid input,
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-flaggedElement-invalid textarea {
+ background-color: #ffdddd;
+}
+.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-iconElement input,
+.oo-ui-textInputWidget.oo-ui-iconElement textarea {
+ padding-left: 2.475em;
+}
+.oo-ui-textInputWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
+ width: 1.875em;
+ margin-left: 0.3em;
+}
+.oo-ui-textInputWidget.oo-ui-indicatorElement input,
+.oo-ui-textInputWidget.oo-ui-indicatorElement textarea {
+ padding-right: 2.4875em;
+}
+.oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ width: 0.9375em;
+ margin-right: 0.775em;
+}
+.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: 2.0875em;
+}
+.oo-ui-textInputWidget-labelPosition-before.oo-ui-iconElement > .oo-ui-labelElement-label {
+ margin-left: 2.075em;
+}
+.oo-ui-menuSelectWidget {
+ position: absolute;
+ background: #ffffff;
+ margin-top: -1px;
+ border: 1px solid #cccccc;
+ border-radius: 0 0 0.25em 0.25em;
+ box-shadow: 0 0.15em 1em 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;
+}
+.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: transparent;
+}
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted,
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted.oo-ui-optionWidget-selected {
+ background-color: #e1f3ff;
+}
+.oo-ui-menuSectionOptionWidget {
+ cursor: default;
+ padding: 0.33em 0.75em;
+ color: #888888;
+}
+.oo-ui-dropdownWidget {
+ display: inline-block;
+ position: relative;
+ 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;
+}
+.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 rgba(0, 0, 0, 0.1);
+ border-radius: 0.25em;
+}
+.oo-ui-dropdownWidget-handle:hover {
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.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 0.5em;
+}
+.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.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-dropdownWidget-handle:focus {
+ outline: 0;
+}
+.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-selectFileWidget {
+ display: inline-block;
+ vertical-align: middle;
+ width: 100%;
+ max-width: 50em;
+ margin-right: 0.5em;
+}
+.oo-ui-selectFileWidget-selectButton {
+ display: table-cell;
+ vertical-align: middle;
+}
+.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+ position: relative;
+ overflow: hidden;
+}
+.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button > input[type="file"] {
+ position: absolute;
+ margin: 0;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ z-index: 1;
+ cursor: pointer;
+ /* Push the button part of the native control out of view, as it changes the cursor */
+ padding-top: 100px;
+}
+.oo-ui-selectFileWidget-selectButton.oo-ui-widget-disabled > .oo-ui-buttonElement-button > input[type="file"] {
+ display: none;
+}
+.oo-ui-selectFileWidget-info {
+ width: 100%;
+ display: table-cell;
+ vertical-align: middle;
+ position: relative;
+ overflow: hidden;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ text-overflow: ellipsis;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label > .oo-ui-selectFileWidget-fileType {
+ float: right;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
+.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+ position: absolute;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+ z-index: 2;
+}
+.oo-ui-selectFileWidget-dropTarget {
+ cursor: default;
+}
+.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropTarget {
+ cursor: pointer;
+}
+.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-clearButton,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-clearButton {
+ display: none;
+}
+.oo-ui-selectFileWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+ margin: 0 0 0 0.5em;
+}
+.oo-ui-selectFileWidget-info {
+ height: 2.4em;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ border-radius: 0.25em;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+ right: 0;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
+ left: 0;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+ line-height: 2.3em;
+ margin: 0;
+ overflow: hidden;
+ white-space: nowrap;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ text-overflow: ellipsis;
+ left: 0.5em;
+ right: 0.5em;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label > .oo-ui-selectFileWidget-fileType {
+ color: #888888;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+ top: 0;
+ width: 1.875em;
+ margin-right: 0;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ height: 2.3em;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+ top: 0;
+ width: 0.9375em;
+ height: 2.3em;
+ margin-right: 0.775em;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
+ top: 0;
+ width: 1.875em;
+ height: 2.3em;
+ margin-left: 0.3em;
+}
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-label {
+ color: #cccccc;
+}
+.oo-ui-selectFileWidget.oo-ui-iconElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+ left: 2.475em;
+}
+.oo-ui-selectFileWidget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+ right: 2.175em;
+}
+.oo-ui-selectFileWidget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-clearButton {
+ right: 0;
+}
+.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+ right: 4.2625em;
+}
+.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-clearButton {
+ right: 2.0875em;
+}
+.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+ right: 0.5em;
+}
+.oo-ui-selectFileWidget-empty.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label,
+.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+ right: 2em;
+}
+.oo-ui-selectFileWidget-dropTarget {
+ line-height: 3.5em;
+ border: 1px dashed #aaaaaa;
+ padding: 0.5em 1em;
+ margin-bottom: 0.5em;
+ background: #ffffff;
+ text-align: center;
+ vertical-align: middle;
+}
+.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropTarget:hover,
+.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop oo-ui-selectfilewidget-droptarget {
+ background-color: #e1f3ff;
+}
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.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: #a7dcff;
+ text-shadow: 0 1px 1px rgba(255, 255, 255, 0.5);
+}
+.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;
+}
+.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: #eeeeee;
+ box-shadow: inset 0 -0.015em 0.1em rgba(0, 0, 0, 0.1);
+}
+.oo-ui-tabOptionWidget {
+ display: inline-block;
+ vertical-align: bottom;
+ padding: 0.5em 1em;
+ margin: 0.5em 0 0 0.75em;
+ border: 1px solid transparent;
+ border-bottom: none;
+ border-top-left-radius: 0.5em;
+ border-top-right-radius: 0.5em;
+}
+.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-pressed {
+ background-color: transparent;
+}
+.oo-ui-tabOptionWidget.oo-ui-widget-enabled:hover {
+ background-color: rgba(255, 255, 255, 0.2);
+ border-color: #dddddd;
+}
+.oo-ui-tabOptionWidget.oo-ui-widget-enabled:active {
+ background-color: #ffffff;
+ border-color: #dddddd;
+}
+.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;
+ border-color: #dddddd;
+}
+.oo-ui-capsuleMultiSelectWidget {
+ display: inline-block;
+ position: relative;
+ width: 100%;
+ max-width: 50em;
+}
+.oo-ui-capsuleMultiSelectWidget-handle {
+ width: 100%;
+ display: inline-block;
+ position: relative;
+}
+.oo-ui-capsuleMultiSelectWidget-group {
+ display: inline;
+}
+.oo-ui-capsuleMultiSelectWidget > .oo-ui-menuSelectWidget {
+ z-index: 1;
+ width: 100%;
+}
+.oo-ui-capsuleMultiSelectWidget-handle {
+ background-color: #ffffff;
+ cursor: text;
+ min-height: 2.4em;
+ margin-right: 0.5em;
+ padding: 0.25em 0;
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ border-radius: 0.25em;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-capsuleMultiSelectWidget-handle:last-child {
+ margin-right: 0;
+}
+.oo-ui-capsuleMultiSelectWidget-handle .oo-ui-capsuleMultiSelectWidget-group {
+ margin: 0 0.2em;
+}
+.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator,
+.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon {
+ position: absolute;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-capsuleMultiSelectWidget-handle > input {
+ border: none;
+ min-width: 1em;
+ max-width: 100%;
+ line-height: 1.675em;
+ margin: 0;
+ padding: 0;
+ font-size: inherit;
+ font-family: inherit;
+ background-color: transparent;
+ color: black;
+ vertical-align: middle;
+}
+.oo-ui-capsuleMultiSelectWidget-handle > input:focus {
+ outline: none;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiSelectWidget-handle {
+ padding-right: 0.9375em;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator {
+ right: 0;
+ top: 0;
+ width: 0.9375em;
+ height: 0.9375em;
+ margin: 0.775em;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-iconElement .oo-ui-capsuleMultiSelectWidget-handle {
+ padding-left: 1.875em;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-iconElement .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon {
+ left: 0;
+ top: 0;
+ width: 1.875em;
+ height: 1.875em;
+ margin: 0.3em;
+}
+.oo-ui-capsuleMultiSelectWidget:hover .oo-ui-capsuleMultiSelectWidget-handle {
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+ cursor: default;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon,
+.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-capsuleMultiSelectWidget .oo-ui-selectWidget {
+ border-top-color: #ffffff;
+}
+.oo-ui-capsuleItemWidget {
+ position: relative;
+ display: inline-block;
+ cursor: default;
+ white-space: nowrap;
+ width: auto;
+ max-width: 100%;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ vertical-align: middle;
+ padding: 0 0.4em;
+ margin: 0 0.1em;
+ height: 1.7em;
+ line-height: 1.7em;
+ 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: -o-linear-gradient(top, #ffffff 0%, #dddddd 100%);
+ background-image: linear-gradient(to bottom, #ffffff 0%, #dddddd 100%);
+ border: 1px solid #cccccc;
+ color: #555555;
+ border-radius: 0.25em;
+}
+.oo-ui-capsuleItemWidget > .oo-ui-iconElement-icon {
+ cursor: pointer;
+}
+.oo-ui-capsuleItemWidget.oo-ui-widget-disabled > .oo-ui-iconElement-icon {
+ cursor: default;
+}
+.oo-ui-capsuleItemWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ display: block;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-labelElement-label {
+ padding-right: 1.3375em;
+}
+.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-indicatorElement-indicator {
+ position: absolute;
+ right: 0.4em;
+ top: 0;
+ width: 0.9375em;
+ height: 100%;
+ background-repeat: no-repeat;
+}
+.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-indicator-clear {
+ cursor: pointer;
+}
+.oo-ui-capsuleItemWidget.oo-ui-widget-disabled {
+ opacity: 0.5;
+ -webkit-transform: translate3d(0, 0, 0);
+ box-shadow: none;
+ color: #333333;
+ background: #eeeeee;
+ border-color: #cccccc;
+}
+.oo-ui-capsuleItemWidget.oo-ui-widget-disabled > .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.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 > .oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
+ cursor: pointer;
+}
+.oo-ui-comboBoxWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-comboBoxWidget-handle {
+ border: 1px solid rgba(0, 0, 0, 0.1);
+ border-radius: 0.25em;
+}
+.oo-ui-comboBoxWidget-handle:hover {
+ border-color: rgba(0, 0, 0, 0.2);
+}
+.oo-ui-comboBoxWidget.oo-ui-widget-disabled .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator,
+.oo-ui-comboBoxWidget-empty .oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
+ cursor: default;
+ opacity: 0.2;
+}
+.oo-ui-comboBoxWidget > .oo-ui-selectWidget {
+ margin-top: -3px;
+}
+.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-numberInputWidget {
+ display: inline-block;
+ position: relative;
+ max-width: 50em;
+}
+.oo-ui-numberInputWidget-field {
+ display: table;
+ table-layout: fixed;
+ width: 100%;
+}
+.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget,
+.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget {
+ display: table-cell;
+ vertical-align: middle;
+}
+.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget {
+ width: 100%;
+}
+.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget {
+ white-space: nowrap;
+}
+.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget > .oo-ui-buttonElement-button {
+ box-sizing: border-box;
+}
+.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget,
+.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget > .oo-ui-buttonElement-button {
+ margin: 0;
+ width: 2.5em;
+}
+.oo-ui-numberInputWidget-minusButton.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ border-right-width: 0;
+}
+.oo-ui-numberInputWidget-plusButton.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ border-left-width: 0;
+}
+.oo-ui-numberInputWidget .oo-ui-textInputWidget input {
+ border-radius: 0;
+}
+.oo-ui-window {
+ background-color: transparent;
+ background-image: none;
+}
+.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 {
+ 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: 1px solid #e5e5e5;
+ margin: 0;
+}
+.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;
+ margin: 0;
+}
+.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
+ border-bottom-width: 0;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget {
+ height: 3.4em;
+ margin-right: 0;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:last-child {
+ margin-right: 0;
+}
+.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-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.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;
+}
+.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;
+ /* Adjust for border so text aligns with title */
+ margin: -1px;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-frameless {
+ margin: 0;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-frameless .oo-ui-buttonElement-button {
+ padding: 0.75em 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-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-actions-other .oo-ui-actionWidget.oo-ui-buttonElement {
+ margin-right: 0;
+}
+.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;
+ -moz-transition: opacity 250ms ease;
+ -ms-transition: opacity 250ms ease;
+ -o-transition: opacity 250ms ease;
+ transition: opacity 250ms ease;
+}
+.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;
+ -moz-transition: all 250ms ease;
+ -ms-transition: all 250ms ease;
+ -o-transition: all 250ms ease;
+ transition: all 250ms ease;
+}
+.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 #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.js b/resources/lib/oojs-ui/oojs-ui-apex.js
new file mode 100644
index 00000000..dab3c78d
--- /dev/null
+++ b/resources/lib/oojs-ui/oojs-ui-apex.js
@@ -0,0 +1,28 @@
+/*!
+ * OOjs UI v0.12.12
+ * https://www.mediawiki.org/wiki/OOjs_UI
+ *
+ * Copyright 2011–2015 OOjs UI Team and other contributors.
+ * Released under the MIT license
+ * http://oojs.mit-license.org
+ *
+ * Date: 2015-10-13T20:38:18Z
+ */
+/**
+ * @class
+ * @extends OO.ui.Theme
+ *
+ * @constructor
+ */
+OO.ui.ApexTheme = function OoUiApexTheme() {
+ // Parent constructor
+ OO.ui.ApexTheme.parent.call( this );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.ApexTheme, OO.ui.Theme );
+
+/* Instantiation */
+
+OO.ui.theme = new OO.ui.ApexTheme();
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-alerts.css b/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-alerts.css
deleted file mode 100644
index 545c64d0..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-alerts.css
+++ /dev/null
@@ -1,64 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index acd14255..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-content.css
+++ /dev/null
@@ -1,76 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index 5f4cb821..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-advanced.css
+++ /dev/null
@@ -1,166 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index 7f3b236f..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-core.css
+++ /dev/null
@@ -1,88 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index 9708223a..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-list.css
+++ /dev/null
@@ -1,34 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index ce739dcb..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-editing-styling.css
+++ /dev/null
@@ -1,495 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index 23bad66d..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-interactions.css
+++ /dev/null
@@ -1,106 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index 35ad9012..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-layout.css
+++ /dev/null
@@ -1,100 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index d7dad243..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-location.css
+++ /dev/null
@@ -1,34 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index 650cfa2f..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-media.css
+++ /dev/null
@@ -1,46 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index 97eb0d52..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-moderation.css
+++ /dev/null
@@ -1,148 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index 148b54e5..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-movement.css
+++ /dev/null
@@ -1,64 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index 9eabc174..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-user.css
+++ /dev/null
@@ -1,34 +0,0 @@
-/*!
- * 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
deleted file mode 100644
index 0c905d08..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-icons-wikimedia.css
+++ /dev/null
@@ -1,28 +0,0 @@
-/*!
- * 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
index 12e80c11..a19ebeab 100644
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki-noimages.css
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki-noimages.css
@@ -1,12 +1,12 @@
/*!
- * OOjs UI v0.11.3
+ * OOjs UI v0.12.12
* https://www.mediawiki.org/wiki/OOjs_UI
*
- * Copyright 2011–2015 OOjs Team and other contributors.
+ * Copyright 2011–2015 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-05-12T12:15:44Z
+ * Date: 2015-10-13T20:38:26Z
*/
@-webkit-keyframes oo-ui-progressBarWidget-slide {
from {
@@ -82,8 +82,6 @@
.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;
@@ -109,6 +107,7 @@
}
.oo-ui-buttonElement > .oo-ui-buttonElement-button {
font-weight: bold;
+ text-decoration: none;
}
.oo-ui-buttonElement.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
margin-left: 0;
@@ -116,7 +115,6 @@
.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;
@@ -136,18 +134,25 @@
margin-left: 0.25em;
margin-right: 0.25em;
}
+.oo-ui-buttonElement-frameless > input.oo-ui-buttonElement-button {
+ padding-left: 0.25em;
+ padding-right: 0.25em;
+ color: #333333;
+}
+.oo-ui-buttonElement-frameless.oo-ui-widget-enabled > input.oo-ui-buttonElement-button,
.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 > input.oo-ui-buttonElement-button,
.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;
+ color: #2962cc;
}
.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-progressive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #777777;
+ color: #347bff;
}
.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 {
@@ -156,10 +161,10 @@
}
.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;
+ color: #008064;
}
.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-constructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #777777;
+ color: #00af89;
}
.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 {
@@ -168,10 +173,10 @@
}
.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;
+ color: #8c130d;
}
.oo-ui-buttonElement-frameless.oo-ui-widget-enabled.oo-ui-flaggedElement-destructive > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
- color: #777777;
+ color: #d11d13;
}
.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 {
@@ -181,19 +186,29 @@
.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:focus {
+ box-shadow: none;
+}
.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-iconElement.oo-ui-labelElement > .oo-ui-buttonElement-button,
+.oo-ui-buttonElement-framed.oo-ui-iconElement.oo-ui-indicatorElement > .oo-ui-buttonElement-button {
+ padding-left: 2.4em;
+}
.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button {
margin: 0.1em 0;
- padding: 0.2em 0.8em;
+ padding: 0.5em 1em;
+ min-height: 1.2em;
+ min-width: 1em;
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;
+ position: relative;
+ -webkit-transition: background 100ms ease, color 100ms ease, border-color 100ms ease, box-shadow 100ms ease;
+ -moz-transition: background 100ms ease, color 100ms ease, border-color 100ms ease, box-shadow 100ms ease;
+ -ms-transition: background 100ms ease, color 100ms ease, border-color 100ms ease, box-shadow 100ms ease;
+ -o-transition: background 100ms ease, color 100ms ease, border-color 100ms ease, box-shadow 100ms ease;
+ transition: background 100ms ease, color 100ms ease, border-color 100ms ease, box-shadow 100ms ease;
}
.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button:hover,
.oo-ui-buttonElement-framed > .oo-ui-buttonElement-button:focus {
@@ -201,25 +216,29 @@
}
.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;
+ line-height: 1.2em;
+ display: inline-block;
}
.oo-ui-buttonElement-framed.oo-ui-iconElement > .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
- margin-left: -0.5em;
- margin-right: -0.5em;
+ position: absolute;
+ top: 0.2em;
+ left: 0.5625em;
}
-.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-iconElement.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ margin-left: 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;
+ display: inline-block;
}
.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-indicatorElement.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-indicatorElement-indicator {
+ position: relative;
+ left: 0.2em;
+}
.oo-ui-buttonElement-framed.oo-ui-widget-disabled > .oo-ui-buttonElement-button {
color: #ffffff;
background: #dddddd;
@@ -257,7 +276,7 @@
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-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;
@@ -278,7 +297,7 @@
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-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;
@@ -299,7 +318,7 @@
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-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;
@@ -322,7 +341,7 @@
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-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;
@@ -346,7 +365,7 @@
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-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;
@@ -370,7 +389,7 @@
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-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;
@@ -411,16 +430,21 @@
.oo-ui-iconElement.oo-ui-iconElement-icon {
background-size: contain;
background-position: center center;
+ background-repeat: no-repeat;
}
.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator,
.oo-ui-indicatorElement.oo-ui-indicatorElement-indicator {
background-size: contain;
background-position: center center;
+ background-repeat: no-repeat;
}
.oo-ui-lookupElement > .oo-ui-menuSelectWidget {
z-index: 1;
width: 100%;
}
+.oo-ui-pendingElement-pending {
+ background-image: /* @embed */ url(themes/mediawiki/images/textures/pending.gif);
+}
.oo-ui-bookletLayout-stackLayout.oo-ui-stackLayout-continuous > .oo-ui-panelLayout-scrollable {
overflow-y: hidden;
}
@@ -468,6 +492,12 @@
.oo-ui-indexLayout-stackLayout > .oo-ui-panelLayout {
padding: 1.5em;
}
+.oo-ui-indexLayout > .oo-ui-menuLayout-menu {
+ height: 2.75em;
+}
+.oo-ui-indexLayout > .oo-ui-menuLayout-content {
+ top: 2.75em;
+}
.oo-ui-fieldLayout {
display: block;
margin-bottom: 1em;
@@ -541,13 +571,30 @@
.oo-ui-fieldLayout > .oo-ui-popupButtonWidget:last-child {
margin-right: 0;
}
-.oo-ui-fieldLayout-disabled .oo-ui-labelElement-label {
+.oo-ui-fieldLayout-disabled > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
color: #cccccc;
}
-.oo-ui-actionFieldLayout-field {
+.oo-ui-fieldLayout-messages {
+ list-style: none none;
+ margin: 0;
+ padding: 0;
+ margin-top: 0.25em;
+ margin-left: 0.25em;
+}
+.oo-ui-fieldLayout-messages > li {
+ margin: 0;
+ padding: 0;
display: table;
- table-layout: fixed;
- width: 100%;
+}
+.oo-ui-fieldLayout-messages .oo-ui-iconWidget {
+ display: table-cell;
+ border-right: 0.5em solid transparent;
+}
+.oo-ui-fieldLayout-messages .oo-ui-labelWidget {
+ display: table-cell;
+ padding: 0;
+ line-height: 1.875em;
+ vertical-align: middle;
}
.oo-ui-actionFieldLayout-input,
.oo-ui-actionFieldLayout-button {
@@ -570,8 +617,6 @@
.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;
@@ -626,11 +671,11 @@
.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;
+ -webkit-transition: all 200ms ease;
+ -moz-transition: all 200ms ease;
+ -ms-transition: all 200ms ease;
+ -o-transition: all 200ms ease;
+ transition: all 200ms ease;
}
.oo-ui-menuLayout-menu {
height: 18em;
@@ -642,57 +687,57 @@
right: 18em;
bottom: 18em;
}
-.oo-ui-menuLayout.oo-ui-menuLayout-hideMenu .oo-ui-menuLayout-menu {
+.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 {
+.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 {
+.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 {
+.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 {
+.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 {
+.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 {
+.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 {
+.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 {
+.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 {
+.oo-ui-menuLayout.oo-ui-menuLayout-showMenu.oo-ui-menuLayout-before > .oo-ui-menuLayout-content {
top: 0 !important;
right: 0 !important;
bottom: 0 !important;
@@ -718,10 +763,31 @@
border-radius: 0.2em;
box-shadow: inset 0 -0.2em 0 0 rgba(0, 0, 0, 0.2);
}
+.oo-ui-panelLayout-padded.oo-ui-panelLayout-framed {
+ margin: 1em 0;
+}
.oo-ui-stackLayout-continuous > .oo-ui-panelLayout {
display: block;
position: relative;
}
+.oo-ui-horizontalLayout > .oo-ui-widget {
+ display: inline-block;
+ vertical-align: middle;
+}
+.oo-ui-horizontalLayout > .oo-ui-layout {
+ display: inline-block;
+}
+.oo-ui-horizontalLayout > .oo-ui-layout,
+.oo-ui-horizontalLayout > .oo-ui-widget {
+ margin-right: 0.5em;
+}
+.oo-ui-horizontalLayout > .oo-ui-layout:last-child,
+.oo-ui-horizontalLayout > .oo-ui-widget:last-child {
+ margin-right: 0;
+}
+.oo-ui-horizontalLayout .oo-ui-fieldLayout {
+ margin-bottom: 0;
+}
.oo-ui-popupTool .oo-ui-popupWidget-popup,
.oo-ui-popupTool .oo-ui-popupWidget-anchor {
z-index: 4;
@@ -761,10 +827,6 @@
.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;
}
@@ -800,6 +862,7 @@
display: inline;
}
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool.oo-ui-widget-disabled > .oo-ui-tool-link {
+ outline: 0;
cursor: default;
}
.oo-ui-barToolGroup > .oo-ui-toolGroup-tools > .oo-ui-tool > .oo-ui-tool-link {
@@ -865,10 +928,9 @@
.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 {
+ outline: 0;
cursor: default;
}
.oo-ui-popupToolGroup .oo-ui-toolGroup-tools {
@@ -876,10 +938,6 @@
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;
}
@@ -1003,7 +1061,7 @@
}
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
padding-left: 0.5em;
- color: #000000;
+ color: #555555;
}
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-accel,
.oo-ui-popupToolGroup .oo-ui-tool-link .oo-ui-tool-title {
@@ -1088,6 +1146,9 @@
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");
+ background-size: contain;
+ background-position: center center;
+ background-repeat: no-repeat;
}
.oo-ui-menuToolGroup .oo-ui-tool.oo-ui-widget-enabled:hover {
background-color: #eeeeee;
@@ -1163,13 +1224,19 @@
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-buttonElement.oo-ui-labelElement {
+ margin: 0;
}
-.oo-ui-toolbar-actions > .oo-ui-toolbar,
-.oo-ui-toolbar-actions > .oo-ui-buttonElement:last-child {
- margin-right: 0.5em;
+.oo-ui-toolbar-actions > .oo-ui-buttonElement.oo-ui-labelElement > .oo-ui-buttonElement-button {
+ border: 0;
+ border-radius: 0;
+ margin: 0;
+ padding: 0 0.3125em;
+}
+.oo-ui-toolbar-actions > .oo-ui-buttonElement.oo-ui-labelElement > .oo-ui-buttonElement-button > .oo-ui-labelElement-label {
+ margin: 0 1em;
+ line-height: 3.125em;
+ /* 40/12.8 */
}
.oo-ui-optionWidget {
position: relative;
@@ -1208,8 +1275,6 @@
.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 {
@@ -1264,9 +1329,6 @@
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;
}
@@ -1307,8 +1369,6 @@
.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;
@@ -1319,8 +1379,6 @@
.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;
@@ -1388,9 +1446,15 @@
-o-transform: translateZ(0px);
transform: translateZ(0px);
height: 2em;
- width: 4em;
+ width: 3.5em;
border-radius: 1em;
- border: 1px #dddddd solid;
+ border: 1px #555555 solid;
+ background: #ffffff;
+ -webkit-transition: background-color 100ms ease;
+ -moz-transition: background-color 100ms ease;
+ -ms-transition: background-color 100ms ease;
+ -o-transition: background-color 100ms ease;
+ transition: background-color 100ms ease;
margin-right: 0.5em;
}
.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
@@ -1422,55 +1486,63 @@
margin-right: 0;
}
.oo-ui-toggleSwitchWidget-grip {
- top: 0.25em;
- left: 0.25em;
- width: 1.5em;
- height: 1.5em;
+ top: 0.5em;
+ left: 0.5em;
+ width: 1em;
+ height: 1em;
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;
+ background: #555555;
+ -webkit-transition: left 100ms ease, margin-left 100ms ease;
+ -moz-transition: left 100ms ease, margin-left 100ms ease;
+ -ms-transition: left 100ms ease, margin-left 100ms ease;
+ -o-transition: left 100ms ease, margin-left 100ms ease;
+ transition: left 100ms ease, margin-left 100ms ease;
}
.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;
+ display: none;
}
.oo-ui-toggleSwitchWidget.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
- left: 2.25em;
+ left: 2em;
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;
+ left: 0.5em;
margin-left: 0;
}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled {
- border: 1px #cccccc solid;
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on {
+ background: #347bff;
+ border-color: #347bff;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
+ background: #ffffff;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus {
+ outline: none;
+ border-color: #347bff;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:focus.oo-ui-toggleWidget-on {
+ border-color: #ffffff;
+ box-shadow: 0 0 0 1px #347bff;
}
.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover {
- border-color: #aaaaaa;
+ border-color: #2962cc;
+ box-shadow: 0 0 0 1px #2962cc;
}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled .oo-ui-toggleSwitchWidget-grip {
- background-color: #ffffff;
- border-color: #aaaaaa;
+.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled:hover.oo-ui-toggleWidget-on {
+ background: #2962cc;
+ border-color: #2962cc;
}
-.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:hover.oo-ui-toggleWidget-on .oo-ui-toggleSwitchWidget-grip {
+ background: #ffffff;
}
-.oo-ui-toggleSwitchWidget.oo-ui-widget-enabled.oo-ui-toggleWidget-off .oo-ui-toggleSwitchWidget-glow {
- background-color: #ffffff;
+.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled {
+ background: #dddddd;
+ border-color: #dddddd;
+ outline: 0;
+}
+.oo-ui-toggleSwitchWidget.oo-ui-widget-disabled .oo-ui-toggleSwitchWidget-grip {
+ background: #ffffff;
}
.oo-ui-progressBarWidget {
max-width: 50em;
@@ -1500,9 +1572,6 @@
.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 */
@@ -1532,10 +1601,10 @@
-ms-user-select: none;
user-select: none;
}
-.oo-ui-popupWidget-head .oo-ui-buttonWidget {
+.oo-ui-popupWidget-head > .oo-ui-buttonWidget {
float: right;
}
-.oo-ui-popupWidget-head .oo-ui-labelElement-label {
+.oo-ui-popupWidget-head > .oo-ui-labelElement-label {
float: left;
cursor: default;
}
@@ -1547,7 +1616,7 @@
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);
+ box-shadow: 0 0.15em 0 0 rgba(0, 0, 0, 0.15);
}
.oo-ui-popupWidget-anchored .oo-ui-popupWidget-popup {
margin-top: 9px;
@@ -1575,19 +1644,19 @@
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;
+ -webkit-transition: width 100ms ease, height 100ms ease, left 100ms ease;
+ -moz-transition: width 100ms ease, height 100ms ease, left 100ms ease;
+ -ms-transition: width 100ms ease, height 100ms ease, left 100ms ease;
+ -o-transition: width 100ms ease, height 100ms ease, left 100ms ease;
+ transition: width 100ms ease, height 100ms ease, left 100ms ease;
}
.oo-ui-popupWidget-head {
height: 2.5em;
}
-.oo-ui-popupWidget-head .oo-ui-buttonWidget {
+.oo-ui-popupWidget-head > .oo-ui-buttonWidget {
margin: 0.25em;
}
-.oo-ui-popupWidget-head .oo-ui-labelElement-label {
+.oo-ui-popupWidget-head > .oo-ui-labelElement-label {
margin: 0.75em 1em;
}
.oo-ui-popupWidget-body-padded {
@@ -1618,6 +1687,12 @@
display: inline-block;
vertical-align: middle;
}
+.oo-ui-buttonInputWidget > button,
+.oo-ui-buttonInputWidget > input {
+ border: 0;
+ padding: 0;
+ background-color: transparent;
+}
.oo-ui-checkboxInputWidget {
position: relative;
line-height: 1.6em;
@@ -1631,18 +1706,18 @@
opacity: 0;
z-index: 1;
position: relative;
+ cursor: pointer;
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-transition: background-size 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -moz-transition: background-size 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -ms-transition: background-size 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -o-transition: background-size 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ transition: background-size 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
@@ -1705,14 +1780,17 @@
box-sizing: border-box;
}
.oo-ui-dropdownInputWidget select {
- height: 2.5em;
- padding: 0.5em;
+ background: #ffffff;
+ height: 2.275em;
font-size: inherit;
font-family: inherit;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
border: 1px solid #cccccc;
+ border-radius: 0.1em;
+ padding-left: 1em;
+ vertical-align: middle;
}
.oo-ui-dropdownInputWidget.oo-ui-widget-enabled select:hover,
.oo-ui-dropdownInputWidget.oo-ui-widget-enabled select:focus {
@@ -1737,18 +1815,18 @@
opacity: 0;
z-index: 1;
position: relative;
+ cursor: pointer;
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-transition: background-size 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -moz-transition: background-size 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -ms-transition: background-size 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ -o-transition: background-size 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
+ transition: background-size 200ms cubic-bezier(0.175, 0.885, 0.32, 1.275);
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
@@ -1793,6 +1871,9 @@
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-radioSelectInputWidget .oo-ui-fieldLayout {
+ margin-bottom: 0;
+}
.oo-ui-textInputWidget {
position: relative;
vertical-align: middle;
@@ -1811,6 +1892,21 @@
-moz-box-sizing: border-box;
box-sizing: border-box;
}
+.oo-ui-textInputWidget input[type="search"] {
+ -webkit-appearance: none;
+}
+.oo-ui-textInputWidget input[type="search"]::-ms-clear {
+ display: none;
+}
+.oo-ui-textInputWidget input[type="search"]::-ms-reveal {
+ display: none;
+}
+.oo-ui-textInputWidget input[type="search"]::-webkit-search-decoration,
+.oo-ui-textInputWidget input[type="search"]::-webkit-search-cancel-button,
+.oo-ui-textInputWidget input[type="search"]::-webkit-search-results-button,
+.oo-ui-textInputWidget input[type="search"]::-webkit-search-results-decoration {
+ display: none;
+}
.oo-ui-textInputWidget > .oo-ui-iconElement-icon,
.oo-ui-textInputWidget > .oo-ui-indicatorElement-indicator,
.oo-ui-textInputWidget > .oo-ui-labelElement-label {
@@ -1822,7 +1918,6 @@
position: absolute;
top: 0;
height: 100%;
- background-repeat: no-repeat;
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
@@ -1831,6 +1926,9 @@
}
.oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-iconElement-icon,
.oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
+ cursor: text;
+}
+.oo-ui-textInputWidget.oo-ui-widget-enabled.oo-ui-textInputWidget-type-search > .oo-ui-indicatorElement-indicator {
cursor: pointer;
}
.oo-ui-textInputWidget.oo-ui-labelElement > .oo-ui-labelElement-label {
@@ -1855,6 +1953,7 @@
.oo-ui-textInputWidget input,
.oo-ui-textInputWidget textarea {
padding: 0.5em;
+ line-height: 1.275em;
margin: 0;
font-size: inherit;
font-family: inherit;
@@ -1863,29 +1962,29 @@
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-transition: box-shadow 100ms ease;
+ -moz-transition: box-shadow 100ms ease;
+ -ms-transition: box-shadow 100ms ease;
+ -o-transition: box-shadow 100ms ease;
+ transition: box-shadow 100ms ease;
-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 input.oo-ui-pendingElement-pending,
+.oo-ui-textInputWidget textarea.oo-ui-pendingElement-pending {
+ background-color: transparent;
}
.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);
+ -webkit-transition: border 200ms cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 200ms cubic-bezier(0.39, 0.575, 0.565, 1);
+ -moz-transition: border 200ms cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 200ms cubic-bezier(0.39, 0.575, 0.565, 1);
+ -ms-transition: border 200ms cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 200ms cubic-bezier(0.39, 0.575, 0.565, 1);
+ -o-transition: border 200ms cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 200ms cubic-bezier(0.39, 0.575, 0.565, 1);
+ transition: border 200ms cubic-bezier(0.39, 0.575, 0.565, 1), box-shadow 200ms 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 {
@@ -1928,25 +2027,20 @@
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;
+ padding-left: 2.875em;
}
.oo-ui-textInputWidget.oo-ui-iconElement .oo-ui-iconElement-icon {
- left: 0.4em;
+ left: 0;
width: 1.875em;
- margin-left: 0.1em;
+ margin-left: 0.5em;
height: 100%;
background-position: right center;
}
.oo-ui-textInputWidget.oo-ui-indicatorElement input,
.oo-ui-textInputWidget.oo-ui-indicatorElement textarea {
- padding-right: 1.875em;
+ padding-right: 2.4875em;
}
.oo-ui-textInputWidget.oo-ui-indicatorElement .oo-ui-indicatorElement-indicator {
width: 0.9375em;
@@ -1959,10 +2053,10 @@
color: #888888;
}
.oo-ui-textInputWidget-labelPosition-after.oo-ui-indicatorElement > .oo-ui-labelElement-label {
- margin-right: 2em;
+ margin-right: 2.0875em;
}
.oo-ui-textInputWidget-labelPosition-before.oo-ui-iconElement > .oo-ui-labelElement-label {
- margin-left: 2.5em;
+ margin-right: 2.475em;
}
.oo-ui-menuSelectWidget {
position: absolute;
@@ -1970,8 +2064,7 @@
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);
+ box-shadow: 0 0.15em 0 0 rgba(0, 0, 0, 0.15);
}
.oo-ui-menuSelectWidget input {
position: absolute;
@@ -2015,9 +2108,9 @@
.oo-ui-dropdownWidget {
display: inline-block;
position: relative;
- margin: 0.25em 0;
width: 100%;
max-width: 50em;
+ background: #ffffff;
margin-right: 0.5em;
}
.oo-ui-dropdownWidget-handle {
@@ -2036,8 +2129,6 @@
.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;
@@ -2050,7 +2141,8 @@
margin-right: 0;
}
.oo-ui-dropdownWidget-handle {
- height: 2.5em;
+ padding: 0.5em 0;
+ height: 2.275em;
border: 1px solid #cccccc;
border-radius: 0.1em;
}
@@ -2061,7 +2153,7 @@
left: 0.25em;
}
.oo-ui-dropdownWidget-handle .oo-ui-labelElement-label {
- line-height: 2.5em;
+ line-height: 1.275em;
margin: 0 1em;
}
.oo-ui-dropdownWidget-handle .oo-ui-indicatorElement-indicator {
@@ -2085,6 +2177,9 @@
border-color: #dddddd;
background-color: #f3f3f3;
}
+.oo-ui-dropdownWidget.oo-ui-widget-disabled .oo-ui-dropdownWidget-handle:focus {
+ outline: 0;
+}
.oo-ui-dropdownWidget.oo-ui-widget-disabled .oo-ui-indicatorElement-indicator {
opacity: 0.2;
}
@@ -2097,6 +2192,188 @@
.oo-ui-dropdownWidget .oo-ui-selectWidget {
border-top-color: #ffffff;
}
+.oo-ui-selectFileWidget {
+ display: inline-block;
+ vertical-align: middle;
+ width: 100%;
+ max-width: 50em;
+ margin-right: 0.5em;
+}
+.oo-ui-selectFileWidget-selectButton {
+ display: table-cell;
+ vertical-align: middle;
+}
+.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+ position: relative;
+ overflow: hidden;
+}
+.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button > input[type="file"] {
+ position: absolute;
+ margin: 0;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ width: 100%;
+ height: 100%;
+ opacity: 0;
+ z-index: 1;
+ cursor: pointer;
+ /* Push the button part of the native control out of view, as it changes the cursor */
+ padding-top: 100px;
+}
+.oo-ui-selectFileWidget-selectButton.oo-ui-widget-disabled > .oo-ui-buttonElement-button > input[type="file"] {
+ display: none;
+}
+.oo-ui-selectFileWidget-info {
+ width: 100%;
+ display: table-cell;
+ vertical-align: middle;
+ position: relative;
+ overflow: hidden;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ text-overflow: ellipsis;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label > .oo-ui-selectFileWidget-fileType {
+ float: right;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator,
+.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+ position: absolute;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+ z-index: 2;
+}
+.oo-ui-selectFileWidget-dropTarget {
+ cursor: default;
+}
+.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropTarget {
+ cursor: pointer;
+}
+.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-clearButton,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-clearButton {
+ display: none;
+}
+.oo-ui-selectFileWidget:last-child {
+ margin-right: 0;
+}
+.oo-ui-selectFileWidget-selectButton > .oo-ui-buttonElement-button {
+ margin: 0 0 0 0.5em;
+}
+.oo-ui-selectFileWidget-info {
+ height: 2.4em;
+ border: 1px solid #cccccc;
+ border-radius: 0.1em;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+ right: 0;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
+ left: 0;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label {
+ line-height: 2.3em;
+ margin: 0;
+ overflow: hidden;
+ white-space: nowrap;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ text-overflow: ellipsis;
+ left: 0.5em;
+ right: 0.5em;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-label > .oo-ui-selectFileWidget-fileType {
+ color: #888888;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton {
+ top: 0;
+ width: 1.875em;
+ margin-right: 0;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-selectFileWidget-clearButton .oo-ui-buttonElement-button > .oo-ui-iconElement-icon {
+ height: 2.3em;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+ top: 0;
+ width: 0.9375em;
+ height: 2.3em;
+ margin-right: 0.775em;
+}
+.oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon {
+ top: 0;
+ width: 1.875em;
+ height: 2.3em;
+ margin-left: 0.5em;
+}
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-iconElement-icon,
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-info > .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-label {
+ color: #cccccc;
+}
+.oo-ui-selectFileWidget.oo-ui-iconElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+ left: 2.875em;
+}
+.oo-ui-selectFileWidget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+ right: 2.375em;
+}
+.oo-ui-selectFileWidget .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-clearButton {
+ right: 0;
+}
+.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+ right: 4.4625em;
+}
+.oo-ui-selectFileWidget.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-clearButton {
+ right: 2.0875em;
+}
+.oo-ui-selectFileWidget-empty .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+ right: 0.5em;
+}
+.oo-ui-selectFileWidget-empty.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label,
+.oo-ui-selectFileWidget-notsupported.oo-ui-indicatorElement .oo-ui-selectFileWidget-info .oo-ui-selectFileWidget-label {
+ right: 2em;
+}
+.oo-ui-selectFileWidget-dropTarget {
+ line-height: 3.5em;
+ border: 1px dashed #cccccc;
+ padding: 0.5em 1em;
+ margin-bottom: 0.5em;
+ background: #ffffff;
+ text-align: center;
+ vertical-align: middle;
+}
+.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled .oo-ui-selectFileWidget-dropTarget:hover {
+ background-color: #eeeeee;
+}
+.oo-ui-selectFileWidget-supported.oo-ui-widget-enabled.oo-ui-selectFileWidget-canDrop .oo-ui-selectFileWidget-dropTarget {
+ background: rgba(52, 123, 255, 0.1);
+}
+.oo-ui-selectFileWidget.oo-ui-widget-disabled .oo-ui-selectFileWidget-dropTarget,
+.oo-ui-selectFileWidget-notsupported .oo-ui-selectFileWidget-dropTarget {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
.oo-ui-outlineOptionWidget {
position: relative;
cursor: pointer;
@@ -2162,7 +2439,6 @@
.oo-ui-outlineControlsWidget > .oo-ui-iconElement-icon {
float: left;
background-position: right center;
- background-repeat: no-repeat;
}
.oo-ui-outlineControlsWidget-items {
float: left;
@@ -2224,6 +2500,155 @@
background-color: #ffffff;
color: #333333;
}
+.oo-ui-capsuleMultiSelectWidget {
+ display: inline-block;
+ position: relative;
+ width: 100%;
+ max-width: 50em;
+}
+.oo-ui-capsuleMultiSelectWidget-handle {
+ width: 100%;
+ display: inline-block;
+ position: relative;
+}
+.oo-ui-capsuleMultiSelectWidget-group {
+ display: inline;
+}
+.oo-ui-capsuleMultiSelectWidget > .oo-ui-menuSelectWidget {
+ z-index: 1;
+ width: 100%;
+}
+.oo-ui-capsuleMultiSelectWidget-handle {
+ background-color: #ffffff;
+ cursor: text;
+ min-height: 2.4em;
+ margin-right: 0.5em;
+ padding: 0.25em 0;
+ border: 1px solid #cccccc;
+ border-radius: 0.1em;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+}
+.oo-ui-capsuleMultiSelectWidget-handle:last-child {
+ margin-right: 0;
+}
+.oo-ui-capsuleMultiSelectWidget-handle .oo-ui-capsuleMultiSelectWidget-group {
+ margin: 0 0.2em;
+}
+.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator,
+.oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon {
+ position: absolute;
+ background-position: center center;
+ background-repeat: no-repeat;
+}
+.oo-ui-capsuleMultiSelectWidget-handle > input {
+ border: none;
+ min-width: 1em;
+ max-width: 100%;
+ line-height: 1.675em;
+ margin: 0;
+ padding: 0;
+ font-size: inherit;
+ font-family: inherit;
+ background-color: transparent;
+ color: black;
+ vertical-align: middle;
+}
+.oo-ui-capsuleMultiSelectWidget-handle > input:focus {
+ outline: none;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiSelectWidget-handle {
+ padding-right: 0.9375em;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-indicatorElement .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator {
+ right: 0;
+ top: 0;
+ width: 0.9375em;
+ height: 0.9375em;
+ margin: 0.775em;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-iconElement .oo-ui-capsuleMultiSelectWidget-handle {
+ padding-left: 1.875em;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-iconElement .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon {
+ left: 0;
+ top: 0;
+ width: 1.875em;
+ height: 1.875em;
+ margin: 0.3em;
+}
+.oo-ui-capsuleMultiSelectWidget:hover .oo-ui-capsuleMultiSelectWidget-handle {
+ border-color: #aaaaaa;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+ cursor: default;
+}
+.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-iconElement-icon,
+.oo-ui-capsuleMultiSelectWidget.oo-ui-widget-disabled .oo-ui-capsuleMultiSelectWidget-handle > .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
+.oo-ui-capsuleMultiSelectWidget .oo-ui-selectWidget {
+ border-top-color: #ffffff;
+}
+.oo-ui-capsuleItemWidget {
+ position: relative;
+ display: inline-block;
+ cursor: default;
+ white-space: nowrap;
+ width: auto;
+ max-width: 100%;
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ vertical-align: middle;
+ padding: 0 0.4em;
+ margin: 0 0.1em;
+ height: 1.7em;
+ line-height: 1.7em;
+ background-color: #eeeeee;
+ border: 1px solid #cccccc;
+ color: #555555;
+ border-radius: 0.1em;
+}
+.oo-ui-capsuleItemWidget > .oo-ui-iconElement-icon {
+ cursor: pointer;
+}
+.oo-ui-capsuleItemWidget.oo-ui-widget-disabled > .oo-ui-iconElement-icon {
+ cursor: default;
+}
+.oo-ui-capsuleItemWidget.oo-ui-labelElement .oo-ui-labelElement-label {
+ display: block;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-labelElement-label {
+ padding-right: 1.3375em;
+}
+.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-indicatorElement-indicator {
+ position: absolute;
+ right: 0.4em;
+ top: 0;
+ width: 0.9375em;
+ height: 100%;
+ background-repeat: no-repeat;
+}
+.oo-ui-capsuleItemWidget.oo-ui-indicatorElement > .oo-ui-indicator-clear {
+ cursor: pointer;
+}
+.oo-ui-capsuleItemWidget.oo-ui-widget-disabled {
+ color: #cccccc;
+ text-shadow: 0 1px 1px #ffffff;
+ border-color: #dddddd;
+ background-color: #f3f3f3;
+}
+.oo-ui-capsuleItemWidget.oo-ui-widget-disabled > .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+}
.oo-ui-comboBoxWidget {
display: inline-block;
position: relative;
@@ -2235,6 +2660,9 @@
z-index: 1;
width: 100%;
}
+.oo-ui-comboBoxWidget > .oo-ui-textInputWidget.oo-ui-widget-enabled > .oo-ui-indicatorElement-indicator {
+ cursor: pointer;
+}
.oo-ui-comboBoxWidget:last-child {
margin-right: 0;
}
@@ -2272,6 +2700,48 @@
padding: 1em;
line-height: 0;
}
+.oo-ui-numberInputWidget {
+ display: inline-block;
+ position: relative;
+ max-width: 50em;
+}
+.oo-ui-numberInputWidget-field {
+ display: table;
+ table-layout: fixed;
+ width: 100%;
+}
+.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget,
+.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget {
+ display: table-cell;
+ vertical-align: middle;
+}
+.oo-ui-numberInputWidget-field > .oo-ui-textInputWidget {
+ width: 100%;
+}
+.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget {
+ white-space: nowrap;
+}
+.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget > .oo-ui-buttonElement-button {
+ box-sizing: border-box;
+}
+.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget,
+.oo-ui-numberInputWidget-field > .oo-ui-buttonWidget > .oo-ui-buttonElement-button {
+ margin: 0;
+ width: 2.5em;
+}
+.oo-ui-numberInputWidget-minusButton.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
+ border-right-width: 0;
+}
+.oo-ui-numberInputWidget-plusButton.oo-ui-buttonElement-framed.oo-ui-widget-enabled > .oo-ui-buttonElement-button {
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+ border-left-width: 0;
+}
+.oo-ui-numberInputWidget .oo-ui-textInputWidget input {
+ border-radius: 0;
+}
.oo-ui-window {
background: transparent;
}
@@ -2383,18 +2853,24 @@
}
.oo-ui-messageDialog-actions-horizontal .oo-ui-actionWidget {
border-right: 1px solid #e5e5e5;
+ margin: 0;
}
.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;
+ margin: 0;
}
.oo-ui-messageDialog-actions-vertical .oo-ui-actionWidget:last-child {
border-bottom-width: 0;
}
.oo-ui-messageDialog-actions .oo-ui-actionWidget {
height: 3.4em;
+ margin-right: 0;
+}
+.oo-ui-messageDialog-actions .oo-ui-actionWidget:last-child {
+ margin-right: 0;
}
.oo-ui-messageDialog-actions .oo-ui-actionWidget.oo-ui-labelElement .oo-ui-labelElement-label {
text-align: center;
@@ -2467,9 +2943,6 @@
.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);
@@ -2489,78 +2962,66 @@
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;
+ margin: 0.5em;
}
-.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;
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-frameless {
+ margin: 0;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless .oo-ui-buttonElement-button,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-frameless .oo-ui-buttonElement-button {
+ padding: 0.75em 1em;
vertical-align: middle;
}
-.oo-ui-processDialog-actions-safe .oo-ui-actionWidget:hover,
-.oo-ui-processDialog-actions-primary .oo-ui-actionWidget:hover {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement-frameless .oo-ui-labelElement-label {
+ line-height: 1.875em;
+}
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless: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 {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless: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 {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-progressive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless.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 {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-progressive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless.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 {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-progressive .oo-ui-labelElement-label,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless.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 {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-constructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless.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 {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-constructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless.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 {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-destructive:hover,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless.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 {
+.oo-ui-processDialog-actions-safe .oo-ui-actionWidget.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-destructive:active,
+.oo-ui-processDialog-actions-primary .oo-ui-actionWidget.oo-ui-buttonElement-frameless.oo-ui-flaggedElement-destructive:active {
background-color: rgba(212, 83, 83, 0.1);
}
+.oo-ui-processDialog-actions-other .oo-ui-actionWidget.oo-ui-buttonElement {
+ margin-right: 0;
+}
.oo-ui-processDialog > .oo-ui-window-frame {
min-height: 5em;
}
@@ -2618,11 +3079,11 @@
.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;
+ -webkit-transition: opacity 250ms ease;
+ -moz-transition: opacity 250ms ease;
+ -ms-transition: opacity 250ms ease;
+ -o-transition: opacity 250ms ease;
+ transition: opacity 250ms ease;
}
.oo-ui-windowManager-modal > .oo-ui-dialog > .oo-ui-window-frame {
top: 1em;
@@ -2634,11 +3095,11 @@
-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;
+ -webkit-transition: all 250ms ease;
+ -moz-transition: all 250ms ease;
+ -ms-transition: all 250ms ease;
+ -o-transition: all 250ms ease;
+ transition: all 250ms ease;
}
.oo-ui-windowManager-modal > .oo-ui-dialog.oo-ui-window-ready {
/* Fade window overlay */
diff --git a/resources/lib/oojs-ui/oojs-ui-mediawiki.css b/resources/lib/oojs-ui/oojs-ui-mediawiki.css
deleted file mode 100644
index 63569f6e..00000000
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki.css
+++ /dev/null
@@ -1,3204 +0,0 @@
-/*!
- * 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
index eaca1f15..e6344f24 100644
--- a/resources/lib/oojs-ui/oojs-ui-mediawiki.js
+++ b/resources/lib/oojs-ui/oojs-ui-mediawiki.js
@@ -1,12 +1,12 @@
/*!
- * OOjs UI v0.11.3
+ * OOjs UI v0.12.12
* https://www.mediawiki.org/wiki/OOjs_UI
*
- * Copyright 2011–2015 OOjs Team and other contributors.
+ * Copyright 2011–2015 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-05-12T12:15:37Z
+ * Date: 2015-10-13T20:38:18Z
*/
/**
* @class
@@ -16,7 +16,7 @@
*/
OO.ui.MediaWikiTheme = function OoUiMediaWikiTheme() {
// Parent constructor
- OO.ui.MediaWikiTheme.super.call( this );
+ OO.ui.MediaWikiTheme.parent.call( this );
};
/* Setup */
@@ -30,7 +30,7 @@ OO.inheritClass( OO.ui.MediaWikiTheme, OO.ui.Theme );
*/
OO.ui.MediaWikiTheme.prototype.getElementClasses = function ( element ) {
// Parent method
- var variant,
+ var variant, isFramed, isActive,
variants = {
warning: false,
invert: false,
@@ -39,12 +39,15 @@ OO.ui.MediaWikiTheme.prototype.getElementClasses = function ( element ) {
destructive: false
},
// Parent method
- classes = OO.ui.MediaWikiTheme.super.prototype.getElementClasses.call( this, element ),
- isFramed;
+ classes = OO.ui.MediaWikiTheme.parent.prototype.getElementClasses.call( this, element );
if ( element.supports( [ 'hasFlag' ] ) ) {
isFramed = element.supports( [ 'isFramed' ] ) && element.isFramed();
- if ( isFramed && ( element.isDisabled() || element.hasFlag( 'primary' ) ) ) {
+ isActive = element.supports( [ 'isActive' ] ) && element.isActive();
+ if (
+ ( isFramed && ( isActive || element.isDisabled() || element.hasFlag( 'primary' ) ) ) ||
+ ( !isFramed && element.hasFlag( 'primary' ) )
+ ) {
variants.invert = true;
} else {
variants.progressive = element.hasFlag( 'progressive' );
diff --git a/resources/lib/oojs-ui/oojs-ui.js b/resources/lib/oojs-ui/oojs-ui.js
index 9692d5cf..aeff69e0 100644
--- a/resources/lib/oojs-ui/oojs-ui.js
+++ b/resources/lib/oojs-ui/oojs-ui.js
@@ -1,12 +1,12 @@
/*!
- * OOjs UI v0.11.3
+ * OOjs UI v0.12.12
* https://www.mediawiki.org/wiki/OOjs_UI
*
- * Copyright 2011–2015 OOjs Team and other contributors.
+ * Copyright 2011–2015 OOjs UI Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-05-12T12:15:37Z
+ * Date: 2015-10-13T20:38:18Z
*/
( function ( OO ) {
@@ -45,36 +45,101 @@ OO.ui.Keys = {
};
/**
+ * @property {Number}
+ */
+OO.ui.elementId = 0;
+
+/**
+ * Generate a unique ID for element
+ *
+ * @return {String} [id]
+ */
+OO.ui.generateElementId = function () {
+ OO.ui.elementId += 1;
+ return 'oojsui-' + OO.ui.elementId;
+};
+
+/**
* 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]
+ * @return {boolean}
*/
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
- );
+ var nodeName,
+ element = $element[ 0 ];
- return (
- ( isInElementGroup ? !node.disabled : isOtherElement ) &&
- isVisible
- );
+ // Anything disabled is not focusable
+ if ( element.disabled ) {
+ return false;
+ }
+
+ // Check if the element is visible
+ if ( !(
+ // This is quicker than calling $element.is( ':visible' )
+ $.expr.filters.visible( element ) &&
+ // Check that all parents are visible
+ !$element.parents().addBack().filter( function () {
+ return $.css( this, 'visibility' ) === 'hidden';
+ } ).length
+ ) ) {
+ return false;
+ }
+
+ // Check if the element is ContentEditable, which is the string 'true'
+ if ( element.contentEditable === 'true' ) {
+ return true;
+ }
+
+ // Anything with a non-negative numeric tabIndex is focusable.
+ // Use .prop to avoid browser bugs
+ if ( $element.prop( 'tabIndex' ) >= 0 ) {
+ return true;
+ }
+
+ // Some element types are naturally focusable
+ // (indexOf is much faster than regex in Chrome and about the
+ // same in FF: https://jsperf.com/regex-vs-indexof-array2)
+ nodeName = element.nodeName.toLowerCase();
+ if ( [ 'input', 'select', 'textarea', 'button', 'object' ].indexOf( nodeName ) !== -1 ) {
+ return true;
+ }
+
+ // Links and areas are focusable if they have an href
+ if ( ( nodeName === 'a' || nodeName === 'area' ) && $element.attr( 'href' ) !== undefined ) {
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ * Find a focusable child
+ *
+ * @param {jQuery} $container Container to search in
+ * @param {boolean} [backwards] Search backwards
+ * @return {jQuery} Focusable child, an empty jQuery object if none found
+ */
+OO.ui.findFocusable = function ( $container, backwards ) {
+ var $focusable = $( [] ),
+ // $focusableCandidates is a superset of things that
+ // could get matched by isFocusableElement
+ $focusableCandidates = $container
+ .find( 'input, select, textarea, button, object, a, area, [contenteditable], [tabindex]' );
+
+ if ( backwards ) {
+ $focusableCandidates = Array.prototype.reverse.call( $focusableCandidates );
+ }
+
+ $focusableCandidates.each( function () {
+ var $this = $( this );
+ if ( OO.ui.isFocusableElement( $this ) ) {
+ $focusable = $this;
+ return false;
+ }
+ } );
+ return $focusable;
};
/**
@@ -183,6 +248,38 @@ OO.ui.debounce = function ( func, wait, immediate ) {
};
/**
+ * Proxy for `node.addEventListener( eventName, handler, true )`, if the browser supports it.
+ * Otherwise falls back to non-capturing event listeners.
+ *
+ * @param {HTMLElement} node
+ * @param {string} eventName
+ * @param {Function} handler
+ */
+OO.ui.addCaptureEventListener = function ( node, eventName, handler ) {
+ if ( node.addEventListener ) {
+ node.addEventListener( eventName, handler, true );
+ } else {
+ node.attachEvent( 'on' + eventName, handler );
+ }
+};
+
+/**
+ * Proxy for `node.removeEventListener( eventName, handler, true )`, if the browser supports it.
+ * Otherwise falls back to non-capturing event listeners.
+ *
+ * @param {HTMLElement} node
+ * @param {string} eventName
+ * @param {Function} handler
+ */
+OO.ui.removeCaptureEventListener = function ( node, eventName, handler ) {
+ if ( node.addEventListener ) {
+ node.removeEventListener( eventName, handler, true );
+ } else {
+ node.detachEvent( 'on' + eventName, handler );
+ }
+};
+
+/**
* Reconstitute a JavaScript object corresponding to a widget created by
* the PHP implementation.
*
@@ -230,7 +327,15 @@ OO.ui.infuse = function ( idOrNode ) {
// 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'
+ 'ooui-dialog-process-continue': 'Continue',
+ // Label for the file selection widget's select file button
+ 'ooui-selectfile-button-select': 'Select a file',
+ // Label for the file selection widget if file selection is not supported
+ 'ooui-selectfile-not-supported': 'File selection is not supported',
+ // Label for the file selection widget when no file is currently selected
+ 'ooui-selectfile-placeholder': 'No file is selected',
+ // Label for the file selection widget's drop target
+ 'ooui-selectfile-dragdrop-placeholder': 'Drop file here'
};
/**
@@ -297,10 +402,102 @@ OO.ui.infuse = function ( idOrNode ) {
return msg;
};
+ /**
+ * @param {string} url
+ * @return {boolean}
+ */
+ OO.ui.isSafeUrl = function ( url ) {
+ var protocol,
+ // Keep in sync with php/Tag.php
+ whitelist = [
+ 'bitcoin:', 'ftp:', 'ftps:', 'geo:', 'git:', 'gopher:', 'http:', 'https:', 'irc:', 'ircs:',
+ 'magnet:', 'mailto:', 'mms:', 'news:', 'nntp:', 'redis:', 'sftp:', 'sip:', 'sips:', 'sms:', 'ssh:',
+ 'svn:', 'tel:', 'telnet:', 'urn:', 'worldwind:', 'xmpp:'
+ ];
+
+ if ( url.indexOf( ':' ) === -1 ) {
+ // No protocol, safe
+ return true;
+ }
+
+ protocol = url.split( ':', 1 )[ 0 ] + ':';
+ if ( !protocol.match( /^([A-za-z0-9\+\.\-])+:/ ) ) {
+ // Not a valid protocol, safe
+ return true;
+ }
+
+ // Safe if in the whitelist
+ return whitelist.indexOf( protocol ) !== -1;
+ };
+
} )();
+/*!
+ * Mixin namespace.
+ */
+
/**
- * Element that can be marked as pending.
+ * Namespace for OOjs UI mixins.
+ *
+ * Mixins are named according to the type of object they are intended to
+ * be mixed in to. For example, OO.ui.mixin.GroupElement is intended to be
+ * mixed in to an instance of OO.ui.Element, and OO.ui.mixin.GroupWidget
+ * is intended to be mixed in to an instance of OO.ui.Widget.
+ *
+ * @class
+ * @singleton
+ */
+OO.ui.mixin = {};
+
+/**
+ * PendingElement is a mixin that is used to create elements that notify users that something is happening
+ * and that they should wait before proceeding. The pending state is visually represented with a pending
+ * texture that appears in the head of a pending {@link OO.ui.ProcessDialog process dialog} or in the input
+ * field of a {@link OO.ui.TextInputWidget text input widget}.
+ *
+ * Currently, {@link OO.ui.ActionWidget Action widgets}, which mix in this class, can also be marked as pending, but only when
+ * used in {@link OO.ui.MessageDialog message dialogs}. The behavior is not currently supported for action widgets used
+ * in process dialogs.
+ *
+ * @example
+ * function MessageDialog( config ) {
+ * MessageDialog.parent.call( this, config );
+ * }
+ * OO.inheritClass( MessageDialog, OO.ui.MessageDialog );
+ *
+ * MessageDialog.static.actions = [
+ * { action: 'save', label: 'Done', flags: 'primary' },
+ * { label: 'Cancel', flags: 'safe' }
+ * ];
+ *
+ * MessageDialog.prototype.initialize = function () {
+ * MessageDialog.parent.prototype.initialize.apply( this, arguments );
+ * this.content = new OO.ui.PanelLayout( { $: this.$, padded: true } );
+ * this.content.$element.append( '<p>Click the \'Done\' action widget to see its pending state. Note that action widgets can be marked pending in message dialogs but not process dialogs.</p>' );
+ * this.$body.append( this.content.$element );
+ * };
+ * MessageDialog.prototype.getBodyHeight = function () {
+ * return 100;
+ * }
+ * MessageDialog.prototype.getActionProcess = function ( action ) {
+ * var dialog = this;
+ * if ( action === 'save' ) {
+ * dialog.getActions().get({actions: 'save'})[0].pushPending();
+ * return new OO.ui.Process()
+ * .next( 1000 )
+ * .next( function () {
+ * dialog.getActions().get({actions: 'save'})[0].popPending();
+ * } );
+ * }
+ * return MessageDialog.parent.prototype.getActionProcess.call( this, action );
+ * };
+ *
+ * var windowManager = new OO.ui.WindowManager();
+ * $( 'body' ).append( windowManager.$element );
+ *
+ * var dialog = new MessageDialog();
+ * windowManager.addWindows( [ dialog ] );
+ * windowManager.openWindow( dialog );
*
* @abstract
* @class
@@ -309,7 +506,7 @@ OO.ui.infuse = function ( idOrNode ) {
* @param {Object} [config] Configuration options
* @cfg {jQuery} [$pending] Element to mark as pending, defaults to this.$element
*/
-OO.ui.PendingElement = function OoUiPendingElement( config ) {
+OO.ui.mixin.PendingElement = function OoUiMixinPendingElement( config ) {
// Configuration initialization
config = config || {};
@@ -323,7 +520,7 @@ OO.ui.PendingElement = function OoUiPendingElement( config ) {
/* Setup */
-OO.initClass( OO.ui.PendingElement );
+OO.initClass( OO.ui.mixin.PendingElement );
/* Methods */
@@ -332,7 +529,7 @@ OO.initClass( OO.ui.PendingElement );
*
* @param {jQuery} $pending The element to set to pending.
*/
-OO.ui.PendingElement.prototype.setPendingElement = function ( $pending ) {
+OO.ui.mixin.PendingElement.prototype.setPendingElement = function ( $pending ) {
if ( this.$pending ) {
this.$pending.removeClass( 'oo-ui-pendingElement-pending' );
}
@@ -344,20 +541,21 @@ OO.ui.PendingElement.prototype.setPendingElement = function ( $pending ) {
};
/**
- * Check if input is pending.
+ * Check if an element is pending.
*
- * @return {boolean}
+ * @return {boolean} Element is pending
*/
-OO.ui.PendingElement.prototype.isPending = function () {
+OO.ui.mixin.PendingElement.prototype.isPending = function () {
return !!this.pending;
};
/**
- * Increase the pending stack.
+ * Increase the pending counter. The pending state will remain active until the counter is zero
+ * (i.e., the number of calls to #pushPending and #popPending is the same).
*
* @chainable
*/
-OO.ui.PendingElement.prototype.pushPending = function () {
+OO.ui.mixin.PendingElement.prototype.pushPending = function () {
if ( this.pending === 0 ) {
this.$pending.addClass( 'oo-ui-pendingElement-pending' );
this.updateThemeClasses();
@@ -368,13 +566,12 @@ OO.ui.PendingElement.prototype.pushPending = function () {
};
/**
- * Reduce the pending stack.
- *
- * Clamped at zero.
+ * Decrease the pending counter. The pending state will remain active until the counter is zero
+ * (i.e., the number of calls to #pushPending and #popPending is the same).
*
* @chainable
*/
-OO.ui.PendingElement.prototype.popPending = function () {
+OO.ui.mixin.PendingElement.prototype.popPending = function () {
if ( this.pending === 1 ) {
this.$pending.removeClass( 'oo-ui-pendingElement-pending' );
this.updateThemeClasses();
@@ -399,7 +596,7 @@ OO.ui.PendingElement.prototype.popPending = function () {
* @example
* // Example: An action set used in a process dialog
* function MyProcessDialog( config ) {
- * MyProcessDialog.super.call( this, config );
+ * MyProcessDialog.parent.call( this, config );
* }
* OO.inheritClass( MyProcessDialog, OO.ui.ProcessDialog );
* MyProcessDialog.static.title = 'An action set in a process dialog';
@@ -412,7 +609,7 @@ OO.ui.PendingElement.prototype.popPending = function () {
* ];
*
* MyProcessDialog.prototype.initialize = function () {
- * MyProcessDialog.super.prototype.initialize.apply( this, arguments );
+ * MyProcessDialog.parent.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 } );
@@ -423,7 +620,7 @@ OO.ui.PendingElement.prototype.popPending = function () {
* this.$body.append( this.stackLayout.$element );
* };
* MyProcessDialog.prototype.getSetupProcess = function ( data ) {
- * return MyProcessDialog.super.prototype.getSetupProcess.call( this, data )
+ * return MyProcessDialog.parent.prototype.getSetupProcess.call( this, data )
* .next( function () {
* this.actions.setMode( 'edit' );
* }, this );
@@ -441,7 +638,7 @@ OO.ui.PendingElement.prototype.popPending = function () {
* dialog.close();
* } );
* }
- * return MyProcessDialog.super.prototype.getActionProcess.call( this, action );
+ * return MyProcessDialog.parent.prototype.getActionProcess.call( this, action );
* };
* MyProcessDialog.prototype.getBodyHeight = function () {
* return this.panel1.$element.outerHeight( true );
@@ -908,7 +1105,8 @@ OO.ui.ActionSet.prototype.organize = function () {
* @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 {jQuery} [$content] Content elements to append (after #text).
+ * @cfg {jQuery} [$element] Wrapper element. Defaults to a new element with #getTagName.
* @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.
*/
@@ -923,8 +1121,7 @@ OO.ui.Element = function OoUiElement( config ) {
this.$element = config.$element ||
$( document.createElement( this.getTagName() ) );
this.elementGroup = null;
- this.debouncedUpdateThemeClassesHandler = this.debouncedUpdateThemeClasses.bind( this );
- this.updateThemeClassesPending = false;
+ this.debouncedUpdateThemeClassesHandler = OO.ui.debounce( this.debouncedUpdateThemeClasses );
// Initialization
if ( Array.isArray( config.classes ) ) {
@@ -991,7 +1188,7 @@ OO.ui.Element.static.tagName = 'div';
* DOM node.
*/
OO.ui.Element.static.infuse = function ( idOrNode ) {
- var obj = OO.ui.Element.static.unsafeInfuse( idOrNode, true );
+ var obj = OO.ui.Element.static.unsafeInfuse( idOrNode, false );
// Verify that the type matches up.
// FIXME: uncomment after T89721 is fixed (see T90929)
/*
@@ -1007,12 +1204,14 @@ OO.ui.Element.static.infuse = function ( idOrNode ) {
* 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.
+ * @param {jQuery.Promise|boolean} domPromise A promise that will be resolved
+ * when the top-level widget of this infusion is inserted into DOM,
+ * replacing the original node; or false for top-level invocation.
* @return {OO.ui.Element}
*/
-OO.ui.Element.static.unsafeInfuse = function ( idOrNode, top ) {
+OO.ui.Element.static.unsafeInfuse = function ( idOrNode, domPromise ) {
// look for a cached result of a previous infusion.
- var id, $elem, data, cls, obj;
+ var id, $elem, data, cls, parts, parent, obj, top, state;
if ( typeof idOrNode === 'string' ) {
id = idOrNode;
$elem = $( document.getElementById( id ) );
@@ -1020,7 +1219,10 @@ OO.ui.Element.static.unsafeInfuse = function ( idOrNode, top ) {
$elem = $( idOrNode );
id = $elem.attr( 'id' );
}
- data = $elem.data( 'ooui-infused' );
+ if ( !$elem.length ) {
+ throw new Error( 'Widget not found: ' + id );
+ }
+ data = $elem.data( 'ooui-infused' ) || $elem[ 0 ].oouiInfused;
if ( data ) {
// cached!
if ( data === true ) {
@@ -1028,9 +1230,6 @@ OO.ui.Element.static.unsafeInfuse = function ( idOrNode, top ) {
}
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 );
@@ -1047,16 +1246,43 @@ OO.ui.Element.static.unsafeInfuse = function ( idOrNode, top ) {
// 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 );
+ parts = data._.split( '.' );
+ cls = OO.getProp.apply( OO, [ window ].concat( parts ) );
+ if ( cls === undefined ) {
+ // The PHP output might be old and not including the "OO.ui" prefix
+ // TODO: Remove this back-compat after next major release
+ cls = OO.getProp.apply( OO, [ OO.ui ].concat( parts ) );
+ if ( cls === undefined ) {
+ throw new Error( 'Unknown widget type: id: ' + id + ', class: ' + data._ );
+ }
+ }
+
+ // Verify that we're creating an OO.ui.Element instance
+ parent = cls.parent;
+
+ while ( parent !== undefined ) {
+ if ( parent === OO.ui.Element ) {
+ // Safe
+ break;
+ }
+
+ parent = parent.parent;
+ }
+
+ if ( parent !== OO.ui.Element ) {
+ throw new Error( 'Unknown widget type: id: ' + id + ', class: ' + data._ );
+ }
+
+ if ( domPromise === false ) {
+ top = $.Deferred();
+ domPromise = top.promise();
}
$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 );
+ return OO.ui.Element.static.unsafeInfuse( value.tag, domPromise );
}
if ( value.html ) {
return new OO.ui.HtmlSnippet( value.html );
@@ -1065,13 +1291,22 @@ OO.ui.Element.static.unsafeInfuse = function ( idOrNode, top ) {
} );
// jscs:disable requireCapitalizedConstructors
obj = new cls( data ); // rebuild widget
+ // pick up dynamic state, like focus, value of form inputs, scroll position, etc.
+ state = obj.gatherPreInfuseState( $elem );
// now replace old DOM with this new DOM.
if ( top ) {
$elem.replaceWith( obj.$element );
+ // This element is now gone from the DOM, but if anyone is holding a reference to it,
+ // let's allow them to OO.ui.infuse() it and do what they expect (T105828).
+ // Do not use jQuery.data(), as using it on detached nodes leaks memory in 1.x line by design.
+ $elem[ 0 ].oouiInfused = obj;
+ top.resolve();
}
obj.$element.data( 'ooui-infused', obj );
// set the 'data-ooui' attribute so we can identify infused widgets
obj.$element.attr( 'data-ooui', '' );
+ // restore dynamic state after the new element is inserted into DOM
+ domPromise.done( obj.restorePreInfuseState.bind( obj, state ) );
return obj;
};
@@ -1128,6 +1363,8 @@ OO.ui.Element.static.getDocument = function ( obj ) {
*/
OO.ui.Element.static.getWindow = function ( obj ) {
var doc = this.getDocument( obj );
+ // Support: IE 8
+ // Standard Document.defaultView is IE9+
return doc.parentWindow || doc.defaultView;
};
@@ -1243,9 +1480,13 @@ OO.ui.Element.static.getRelativePosition = function ( $element, $anchor ) {
*/
OO.ui.Element.static.getBorders = function ( el ) {
var doc = el.ownerDocument,
+ // Support: IE 8
+ // Standard Document.defaultView is IE9+
win = doc.parentWindow || doc.defaultView,
style = win && win.getComputedStyle ?
win.getComputedStyle( el, null ) :
+ // Support: IE 8
+ // Standard getComputedStyle() is IE9+
el.currentStyle,
$el = $( el ),
top = parseFloat( style ? style.borderTopWidth : $el.css( 'borderTopWidth' ) ) || 0,
@@ -1271,6 +1512,8 @@ OO.ui.Element.static.getBorders = function ( el ) {
OO.ui.Element.static.getDimensions = function ( el ) {
var $el, $win,
doc = el.ownerDocument || el.document,
+ // Support: IE 8
+ // Standard Document.defaultView is IE9+
win = doc.parentWindow || doc.defaultView;
if ( win === el || el === doc.documentElement ) {
@@ -1351,11 +1594,12 @@ OO.ui.Element.static.getRootScrollableElement = function ( el ) {
*/
OO.ui.Element.static.getClosestScrollableContainer = function ( el, dimension ) {
var i, val,
- props = [ 'overflow' ],
+ // props = [ 'overflow' ] doesn't work due to https://bugzilla.mozilla.org/show_bug.cgi?id=889091
+ props = [ 'overflow-x', 'overflow-y' ],
$parent = $( el ).parent();
if ( dimension === 'x' || dimension === 'y' ) {
- props.push( 'overflow-' + dimension );
+ props = [ 'overflow-' + dimension ];
}
while ( $parent.length ) {
@@ -1386,16 +1630,18 @@ OO.ui.Element.static.getClosestScrollableContainer = function ( el, dimension )
* @param {Function} [config.complete] Function to call when scrolling completes
*/
OO.ui.Element.static.scrollIntoView = function ( el, config ) {
+ var rel, anim, callback, sc, $sc, eld, scd, $win;
+
// Configuration initialization
config = config || {};
- var rel, anim = {},
- callback = typeof config.complete === 'function' && config.complete,
- sc = this.getClosestScrollableContainer( el, config.direction ),
- $sc = $( sc ),
- eld = this.getDimensions( el ),
- scd = this.getDimensions( sc ),
- $win = $( this.getWindow( el ) );
+ anim = {};
+ callback = typeof config.complete === 'function' && config.complete;
+ sc = this.getClosestScrollableContainer( el, config.direction );
+ $sc = $( sc );
+ eld = this.getDimensions( el );
+ scd = this.getDimensions( sc );
+ $win = $( this.getWindow( el ) );
// Compute the distances between the edges of el and the edges of the scroll viewport
if ( $sc.is( 'html, body' ) ) {
@@ -1458,7 +1704,10 @@ OO.ui.Element.static.scrollIntoView = function ( el, config ) {
* @param {HTMLElement} el Element to reconsider the scrollbars on
*/
OO.ui.Element.static.reconsiderScrollbars = function ( el ) {
- var i, len, nodes = [];
+ var i, len, scrollLeft, scrollTop, nodes = [];
+ // Save scroll position
+ scrollLeft = el.scrollLeft;
+ scrollTop = el.scrollTop;
// Detach all children
while ( el.firstChild ) {
nodes.push( el.firstChild );
@@ -1470,6 +1719,9 @@ OO.ui.Element.static.reconsiderScrollbars = function ( el ) {
for ( i = 0, len = nodes.length; i < len; i++ ) {
el.appendChild( nodes[ i ] );
}
+ // Restore scroll position (no-op if scrollbars disappeared)
+ el.scrollLeft = scrollLeft;
+ el.scrollTop = scrollTop;
};
/* Methods */
@@ -1550,18 +1802,16 @@ OO.ui.Element.prototype.supports = function ( methods ) {
* 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 );
- }
+ this.debouncedUpdateThemeClassesHandler();
};
/**
* @private
+ * @localdoc This method is called directly from the QUnit tests instead of #updateThemeClasses, to
+ * make them synchronous.
*/
OO.ui.Element.prototype.debouncedUpdateThemeClasses = function () {
OO.ui.theme.updateElementClasses( this );
- this.updateThemeClassesPending = false;
};
/**
@@ -1612,7 +1862,7 @@ OO.ui.Element.prototype.getClosestScrollableElementContainer = function () {
/**
* Get group element is in.
*
- * @return {OO.ui.GroupElement|null} Group element, null if none
+ * @return {OO.ui.mixin.GroupElement|null} Group element, null if none
*/
OO.ui.Element.prototype.getElementGroup = function () {
return this.elementGroup;
@@ -1621,7 +1871,7 @@ OO.ui.Element.prototype.getElementGroup = function () {
/**
* Set group element is in.
*
- * @param {OO.ui.GroupElement|null} group Group element, null if none
+ * @param {OO.ui.mixin.GroupElement|null} group Group element, null if none
* @chainable
*/
OO.ui.Element.prototype.setElementGroup = function ( group ) {
@@ -1639,11 +1889,40 @@ OO.ui.Element.prototype.scrollElementIntoView = function ( config ) {
};
/**
+ * Gather the dynamic state (focus, value of form inputs, scroll position, etc.) of a HTML DOM node
+ * (and its children) that represent an Element of the same type and configuration as the current
+ * one, generated by the PHP implementation.
+ *
+ * This method is called just before `node` is detached from the DOM. The return value of this
+ * function will be passed to #restorePreInfuseState after this widget's #$element is inserted into
+ * DOM to replace `node`.
+ *
+ * @protected
+ * @param {HTMLElement} node
+ * @return {Object}
+ */
+OO.ui.Element.prototype.gatherPreInfuseState = function () {
+ return {};
+};
+
+/**
+ * Restore the pre-infusion dynamic state for this widget.
+ *
+ * This method is called after #$element has been inserted into DOM. The parameter is the return
+ * value of #gatherPreInfuseState.
+ *
+ * @protected
+ * @param {Object} state
+ */
+OO.ui.Element.prototype.restorePreInfuseState = function () {
+};
+
+/**
* 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.
+ * {@link OO.ui.HorizontalLayout HorizontalLayout}, and {@link OO.ui.BookletLayout BookletLayout} for more information and examples.
*
* @abstract
* @class
@@ -1658,7 +1937,7 @@ OO.ui.Layout = function OoUiLayout( config ) {
config = config || {};
// Parent constructor
- OO.ui.Layout.super.call( this, config );
+ OO.ui.Layout.parent.call( this, config );
// Mixin constructors
OO.EventEmitter.call( this );
@@ -1692,7 +1971,7 @@ OO.ui.Widget = function OoUiWidget( config ) {
config = $.extend( { disabled: false }, config );
// Parent constructor
- OO.ui.Widget.super.call( this, config );
+ OO.ui.Widget.parent.call( this, config );
// Mixin constructors
OO.EventEmitter.call( this );
@@ -1711,12 +1990,26 @@ OO.ui.Widget = function OoUiWidget( config ) {
OO.inheritClass( OO.ui.Widget, OO.ui.Element );
OO.mixinClass( OO.ui.Widget, OO.EventEmitter );
+/* Static Properties */
+
+/**
+ * Whether this widget will behave reasonably when wrapped in a HTML `<label>`. If this is true,
+ * wrappers such as OO.ui.FieldLayout may use a `<label>` instead of implementing own label click
+ * handling.
+ *
+ * @static
+ * @inheritable
+ * @property {boolean}
+ */
+OO.ui.Widget.static.supportsSimpleLabel = false;
+
/* Events */
/**
* @event disable
*
- * A 'disable' event is emitted when a widget is disabled.
+ * A 'disable' event is emitted when the disabled state of the widget changes
+ * (i.e. on disable **and** enable).
*
* @param {boolean} disabled Widget is disabled
*/
@@ -1825,7 +2118,7 @@ OO.ui.Window = function OoUiWindow( config ) {
config = config || {};
// Parent constructor
- OO.ui.Window.super.call( this, config );
+ OO.ui.Window.parent.call( this, config );
// Mixin constructors
OO.EventEmitter.call( this );
@@ -1837,6 +2130,10 @@ OO.ui.Window = function OoUiWindow( config ) {
this.$overlay = $( '<div>' );
this.$content = $( '<div>' );
+ this.$focusTrapBefore = $( '<div>' ).prop( 'tabIndex', 0 );
+ this.$focusTrapAfter = $( '<div>' ).prop( 'tabIndex', 0 );
+ this.$focusTraps = this.$focusTrapBefore.add( this.$focusTrapAfter );
+
// Initialization
this.$overlay.addClass( 'oo-ui-window-overlay' );
this.$content
@@ -1844,7 +2141,7 @@ OO.ui.Window = function OoUiWindow( config ) {
.attr( 'tabindex', 0 );
this.$frame
.addClass( 'oo-ui-window-frame' )
- .append( this.$content );
+ .append( this.$focusTrapBefore, this.$content, this.$focusTrapAfter );
this.$element
.addClass( 'oo-ui-window' )
@@ -1962,7 +2259,27 @@ OO.ui.Window.prototype.getManager = function () {
* @return {string} Symbolic name of the size: `small`, `medium`, `large`, `larger`, `full`
*/
OO.ui.Window.prototype.getSize = function () {
- return this.size;
+ var viewport = OO.ui.Element.static.getDimensions( this.getElementWindow() ),
+ sizes = this.manager.constructor.static.sizes,
+ size = this.size;
+
+ if ( !sizes[ size ] ) {
+ size = this.manager.constructor.static.defaultSize;
+ }
+ if ( size !== 'full' && viewport.rect.right - viewport.rect.left < sizes[ size ].width ) {
+ size = 'full';
+ }
+
+ return size;
+};
+
+/**
+ * Get the size properties associated with the current window size
+ *
+ * @return {Object} Size properties
+ */
+OO.ui.Window.prototype.getSizeProperties = function () {
+ return this.manager.constructor.static.sizes[ this.getSize() ];
};
/**
@@ -2048,7 +2365,7 @@ OO.ui.Window.prototype.getBodyHeight = function () {
* @return {string} Directionality: `'ltr'` or `'rtl'`
*/
OO.ui.Window.prototype.getDir = function () {
- return this.dir;
+ return OO.ui.Element.static.getDir( this.$content ) || 'ltr';
};
/**
@@ -2243,7 +2560,6 @@ OO.ui.Window.prototype.initialize = function () {
this.$head = $( '<div>' );
this.$body = $( '<div>' );
this.$foot = $( '<div>' );
- this.dir = OO.ui.Element.static.getDir( this.$content ) || 'ltr';
this.$document = $( this.getElementDocument() );
// Events
@@ -2259,6 +2575,21 @@ OO.ui.Window.prototype.initialize = function () {
};
/**
+ * Called when someone tries to focus the hidden element at the end of the dialog.
+ * Sends focus back to the start of the dialog.
+ *
+ * @param {jQuery.Event} event Focus event
+ */
+OO.ui.Window.prototype.onFocusTrapFocused = function ( event ) {
+ if ( this.$focusTrapBefore.is( event.target ) ) {
+ OO.ui.findFocusable( this.$content, true ).focus();
+ } else {
+ // this.$content is the part of the focus cycle, and is the first focusable element
+ this.$content.focus();
+ }
+};
+
+/**
* Open the window.
*
* This method is a wrapper around a call to the window manager’s {@link OO.ui.WindowManager#openWindow openWindow}
@@ -2318,6 +2649,9 @@ OO.ui.Window.prototype.setup = function ( data ) {
this.toggle( true );
+ this.focusTrapHandler = OO.ui.bind( this.onFocusTrapFocused, this );
+ this.$focusTraps.on( 'focus', this.focusTrapHandler );
+
this.getSetupProcess( data ).execute().done( function () {
// Force redraw by asking the browser to measure the elements' widths
win.$element.addClass( 'oo-ui-window-active oo-ui-window-setup' ).width();
@@ -2400,6 +2734,7 @@ OO.ui.Window.prototype.teardown = function ( data ) {
// 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.$focusTraps.off( 'focus', win.focusTrapHandler );
win.toggle( false );
} );
};
@@ -2414,11 +2749,11 @@ OO.ui.Window.prototype.teardown = function ( data ) {
* @example
* // A simple dialog window.
* function MyDialog( config ) {
- * MyDialog.super.call( this, config );
+ * MyDialog.parent.call( this, config );
* }
* OO.inheritClass( MyDialog, OO.ui.Dialog );
* MyDialog.prototype.initialize = function () {
- * MyDialog.super.prototype.initialize.call( this );
+ * MyDialog.parent.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 );
@@ -2441,23 +2776,23 @@ OO.ui.Window.prototype.teardown = function ( data ) {
* @abstract
* @class
* @extends OO.ui.Window
- * @mixins OO.ui.PendingElement
+ * @mixins OO.ui.mixin.PendingElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
OO.ui.Dialog = function OoUiDialog( config ) {
// Parent constructor
- OO.ui.Dialog.super.call( this, config );
+ OO.ui.Dialog.parent.call( this, config );
// Mixin constructors
- OO.ui.PendingElement.call( this );
+ OO.ui.mixin.PendingElement.call( this );
// Properties
this.actions = new OO.ui.ActionSet();
this.attachedActions = [];
this.currentAction = null;
- this.onDocumentKeyDownHandler = this.onDocumentKeyDown.bind( this );
+ this.onDialogKeyDownHandler = this.onDialogKeyDown.bind( this );
// Events
this.actions.connect( this, {
@@ -2475,7 +2810,7 @@ OO.ui.Dialog = function OoUiDialog( config ) {
/* Setup */
OO.inheritClass( OO.ui.Dialog, OO.ui.Window );
-OO.mixinClass( OO.ui.Dialog, OO.ui.PendingElement );
+OO.mixinClass( OO.ui.Dialog, OO.ui.mixin.PendingElement );
/* Static Properties */
@@ -2497,7 +2832,7 @@ OO.ui.Dialog.static.name = '';
/**
* The dialog title.
*
- * The title can be specified as a plaintext string, a {@link OO.ui.LabelElement Label} node, or a function
+ * The title can be specified as a plaintext string, a {@link OO.ui.mixin.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.
*
@@ -2540,7 +2875,7 @@ OO.ui.Dialog.static.escapable = true;
* @private
* @param {jQuery.Event} e Key down event
*/
-OO.ui.Dialog.prototype.onDocumentKeyDown = function ( e ) {
+OO.ui.Dialog.prototype.onDialogKeyDown = function ( e ) {
if ( e.which === OO.ui.Keys.ESCAPE ) {
this.close();
e.preventDefault();
@@ -2626,7 +2961,7 @@ OO.ui.Dialog.prototype.getSetupProcess = function ( data ) {
data = data || {};
// Parent method
- return OO.ui.Dialog.super.prototype.getSetupProcess.call( this, data )
+ return OO.ui.Dialog.parent.prototype.getSetupProcess.call( this, data )
.next( function () {
var config = this.constructor.static,
actions = data.actions !== undefined ? data.actions : config.actions;
@@ -2637,7 +2972,7 @@ OO.ui.Dialog.prototype.getSetupProcess = function ( data ) {
this.actions.add( this.getActionWidgets( actions ) );
if ( this.constructor.static.escapable ) {
- this.$document.on( 'keydown', this.onDocumentKeyDownHandler );
+ this.$element.on( 'keydown', this.onDialogKeyDownHandler );
}
}, this );
};
@@ -2647,10 +2982,10 @@ OO.ui.Dialog.prototype.getSetupProcess = function ( data ) {
*/
OO.ui.Dialog.prototype.getTeardownProcess = function ( data ) {
// Parent method
- return OO.ui.Dialog.super.prototype.getTeardownProcess.call( this, data )
+ return OO.ui.Dialog.parent.prototype.getTeardownProcess.call( this, data )
.first( function () {
if ( this.constructor.static.escapable ) {
- this.$document.off( 'keydown', this.onDocumentKeyDownHandler );
+ this.$element.off( 'keydown', this.onDialogKeyDownHandler );
}
this.actions.clear();
@@ -2662,14 +2997,21 @@ OO.ui.Dialog.prototype.getTeardownProcess = function ( data ) {
* @inheritdoc
*/
OO.ui.Dialog.prototype.initialize = function () {
+ var titleId;
+
// Parent method
- OO.ui.Dialog.super.prototype.initialize.call( this );
+ OO.ui.Dialog.parent.prototype.initialize.call( this );
+
+ titleId = OO.ui.generateElementId();
// Properties
- this.title = new OO.ui.LabelWidget();
+ this.title = new OO.ui.LabelWidget( {
+ id: titleId
+ } );
// Initialization
this.$content.addClass( 'oo-ui-dialog-content' );
+ this.$element.attr( 'aria-labelledby', titleId );
this.setPendingElement( this.$head );
};
@@ -2789,7 +3131,7 @@ OO.ui.WindowManager = function OoUiWindowManager( config ) {
config = config || {};
// Parent constructor
- OO.ui.WindowManager.super.call( this, config );
+ OO.ui.WindowManager.parent.call( this, config );
// Mixin constructors
OO.EventEmitter.call( this );
@@ -3286,25 +3628,18 @@ OO.ui.WindowManager.prototype.clearWindows = function () {
* @chainable
*/
OO.ui.WindowManager.prototype.updateWindowSize = function ( win ) {
+ var isFullscreen;
+
// Bypass for non-current, and thus invisible, windows
if ( win !== this.currentWindow ) {
return;
}
- var viewport = OO.ui.Element.static.getDimensions( win.getElementWindow() ),
- sizes = this.constructor.static.sizes,
- size = win.getSize();
-
- if ( !sizes[ size ] ) {
- size = this.constructor.static.defaultSize;
- }
- if ( size !== 'full' && viewport.rect.right - viewport.rect.left < sizes[ size ].width ) {
- size = 'full';
- }
+ isFullscreen = win.getSize() === 'full';
- this.$element.toggleClass( 'oo-ui-windowManager-fullscreen', size === 'full' );
- this.$element.toggleClass( 'oo-ui-windowManager-floating', size !== 'full' );
- win.setDimensions( sizes[ size ] );
+ this.$element.toggleClass( 'oo-ui-windowManager-fullscreen', isFullscreen );
+ this.$element.toggleClass( 'oo-ui-windowManager-floating', !isFullscreen );
+ win.setDimensions( win.getSizeProperties() );
this.emit( 'resize', win );
@@ -3319,14 +3654,14 @@ OO.ui.WindowManager.prototype.updateWindowSize = function ( win ) {
* @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 ;
+ on = on === undefined ? !!this.globalEvents : !!on;
+
if ( on ) {
if ( !this.globalEvents ) {
$( this.getElementWindow() ).on( {
@@ -3694,7 +4029,13 @@ OO.ui.Process.prototype.next = function ( step, context ) {
};
/**
- * Factory for tools.
+ * A ToolFactory creates tools on demand. All tools ({@link OO.ui.Tool Tools}, {@link OO.ui.PopupTool PopupTools},
+ * and {@link OO.ui.ToolGroupTool ToolGroupTools}) must be registered with a tool factory. Tools are
+ * registered by their symbolic name. See {@link OO.ui.Toolbar toolbars} for an example.
+ *
+ * For more information about toolbars in general, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Toolbars
*
* @class
* @extends OO.Factory
@@ -3702,7 +4043,7 @@ OO.ui.Process.prototype.next = function ( step, context ) {
*/
OO.ui.ToolFactory = function OoUiToolFactory() {
// Parent constructor
- OO.ui.ToolFactory.super.call( this );
+ OO.ui.ToolFactory.parent.call( this );
};
/* Setup */
@@ -3815,18 +4156,29 @@ OO.ui.ToolFactory.prototype.extract = function ( collection, used ) {
};
/**
- * Factory for tool groups.
+ * ToolGroupFactories create {@link OO.ui.ToolGroup toolgroups} on demand. The toolgroup classes must
+ * specify a symbolic name and be registered with the factory. The following classes are registered by
+ * default:
+ *
+ * - {@link OO.ui.BarToolGroup BarToolGroups} (‘bar’)
+ * - {@link OO.ui.MenuToolGroup MenuToolGroups} (‘menu’)
+ * - {@link OO.ui.ListToolGroup ListToolGroups} (‘list’)
+ *
+ * See {@link OO.ui.Toolbar toolbars} for an example.
+ *
+ * For more information about toolbars in general, please see the [OOjs UI documentation on MediaWiki][1].
*
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Toolbars
* @class
* @extends OO.Factory
* @constructor
*/
OO.ui.ToolGroupFactory = function OoUiToolGroupFactory() {
+ var i, l, defaultClasses;
// Parent constructor
OO.Factory.call( this );
- var i, l,
- defaultClasses = this.constructor.static.getDefaultClasses();
+ defaultClasses = this.constructor.static.getDefaultClasses();
// Register default toolgroups
for ( i = 0, l = defaultClasses.length; i < l; i++ ) {
@@ -3841,7 +4193,7 @@ OO.inheritClass( OO.ui.ToolGroupFactory, OO.Factory );
/* Static Methods */
/**
- * Get a default set of classes to be registered on construction
+ * Get a default set of classes to be registered on construction.
*
* @return {Function[]} Default classes
*/
@@ -3882,7 +4234,7 @@ OO.initClass( OO.ui.Theme );
* @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 */ ) {
+OO.ui.Theme.prototype.getElementClasses = function () {
return { on: [], off: [] };
};
@@ -3895,9 +4247,17 @@ OO.ui.Theme.prototype.getElementClasses = function ( /* element */ ) {
* @return {Object.<string,string[]>} Categorized class names with `on` and `off` lists
*/
OO.ui.Theme.prototype.updateElementClasses = function ( element ) {
- var classes = this.getElementClasses( element );
+ var $elements = $( [] ),
+ classes = this.getElementClasses( element );
- element.$element
+ if ( element.$icon ) {
+ $elements = $elements.add( element.$icon );
+ }
+ if ( element.$indicator ) {
+ $elements = $elements.add( element.$indicator );
+ }
+
+ $elements
.removeClass( classes.off.join( ' ' ) )
.addClass( classes.on.join( ' ' ) );
};
@@ -3940,7 +4300,7 @@ OO.ui.Theme.prototype.updateElementClasses = function ( element ) {
* 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 ) {
+OO.ui.mixin.TabIndexedElement = function OoUiMixinTabIndexedElement( config ) {
// Configuration initialization
config = $.extend( { tabIndex: 0 }, config );
@@ -3949,7 +4309,7 @@ OO.ui.TabIndexedElement = function OoUiTabIndexedElement( config ) {
this.tabIndex = null;
// Events
- this.connect( this, { disable: 'onDisable' } );
+ this.connect( this, { disable: 'onTabIndexedElementDisable' } );
// Initialization
this.setTabIndex( config.tabIndex );
@@ -3958,7 +4318,7 @@ OO.ui.TabIndexedElement = function OoUiTabIndexedElement( config ) {
/* Setup */
-OO.initClass( OO.ui.TabIndexedElement );
+OO.initClass( OO.ui.mixin.TabIndexedElement );
/* Methods */
@@ -3972,7 +4332,7 @@ OO.initClass( OO.ui.TabIndexedElement );
* @param {jQuery} $tabIndexed Element that should use the tabindex functionality
* @chainable
*/
-OO.ui.TabIndexedElement.prototype.setTabIndexedElement = function ( $tabIndexed ) {
+OO.ui.mixin.TabIndexedElement.prototype.setTabIndexedElement = function ( $tabIndexed ) {
var tabIndex = this.tabIndex;
// Remove attributes from old $tabIndexed
this.setTabIndex( null );
@@ -3988,7 +4348,7 @@ OO.ui.TabIndexedElement.prototype.setTabIndexedElement = function ( $tabIndexed
* @param {number|null} tabIndex Tabindex value, or `null` for no tabindex
* @chainable
*/
-OO.ui.TabIndexedElement.prototype.setTabIndex = function ( tabIndex ) {
+OO.ui.mixin.TabIndexedElement.prototype.setTabIndex = function ( tabIndex ) {
tabIndex = typeof tabIndex === 'number' ? tabIndex : null;
if ( this.tabIndex !== tabIndex ) {
@@ -4006,13 +4366,14 @@ OO.ui.TabIndexedElement.prototype.setTabIndex = function ( tabIndex ) {
* @private
* @chainable
*/
-OO.ui.TabIndexedElement.prototype.updateTabIndex = function () {
+OO.ui.mixin.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
+ // Support: ChromeVox and NVDA
+ // These do not seem to inherit aria-disabled from parent elements
'aria-disabled': this.isDisabled().toString()
} );
} else {
@@ -4028,7 +4389,7 @@ OO.ui.TabIndexedElement.prototype.updateTabIndex = function () {
* @private
* @param {boolean} disabled Element is disabled
*/
-OO.ui.TabIndexedElement.prototype.onDisable = function () {
+OO.ui.mixin.TabIndexedElement.prototype.onTabIndexedElementDisable = function () {
this.updateTabIndex();
};
@@ -4037,7 +4398,7 @@ OO.ui.TabIndexedElement.prototype.onDisable = function () {
*
* @return {number|null} Tabindex value
*/
-OO.ui.TabIndexedElement.prototype.getTabIndex = function () {
+OO.ui.mixin.TabIndexedElement.prototype.getTabIndex = function () {
return this.tabIndex;
};
@@ -4055,16 +4416,14 @@ OO.ui.TabIndexedElement.prototype.getTabIndex = function () {
* @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 ) {
+OO.ui.mixin.ButtonElement = function OoUiMixinButtonElement( config ) {
// Configuration initialization
config = config || {};
// Properties
this.$button = null;
this.framed = null;
- this.accessKey = null;
this.active = false;
this.onMouseUpHandler = this.onMouseUp.bind( this );
this.onMouseDownHandler = this.onMouseDown.bind( this );
@@ -4076,13 +4435,12 @@ OO.ui.ButtonElement = function OoUiButtonElement( config ) {
// Initialization
this.$element.addClass( 'oo-ui-buttonElement' );
this.toggleFramed( config.framed === undefined || config.framed );
- this.setAccessKey( config.accessKey );
this.setButtonElement( config.$button || $( '<a>' ) );
};
/* Setup */
-OO.initClass( OO.ui.ButtonElement );
+OO.initClass( OO.ui.mixin.ButtonElement );
/* Static Properties */
@@ -4090,7 +4448,7 @@ 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}
+ * Classes such as {@link OO.ui.mixin.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.
*
@@ -4098,7 +4456,7 @@ OO.initClass( OO.ui.ButtonElement );
* @inheritable
* @property {boolean}
*/
-OO.ui.ButtonElement.static.cancelButtonMouseDownEvents = true;
+OO.ui.mixin.ButtonElement.static.cancelButtonMouseDownEvents = true;
/* Events */
@@ -4119,7 +4477,7 @@ OO.ui.ButtonElement.static.cancelButtonMouseDownEvents = true;
*
* @param {jQuery} $button Element to use as button
*/
-OO.ui.ButtonElement.prototype.setButtonElement = function ( $button ) {
+OO.ui.mixin.ButtonElement.prototype.setButtonElement = function ( $button ) {
if ( this.$button ) {
this.$button
.removeClass( 'oo-ui-buttonElement-button' )
@@ -4134,7 +4492,7 @@ OO.ui.ButtonElement.prototype.setButtonElement = function ( $button ) {
this.$button = $button
.addClass( 'oo-ui-buttonElement-button' )
- .attr( { role: 'button', accesskey: this.accessKey } )
+ .attr( { role: 'button' } )
.on( {
mousedown: this.onMouseDownHandler,
keydown: this.onKeyDownHandler,
@@ -4149,14 +4507,14 @@ OO.ui.ButtonElement.prototype.setButtonElement = function ( $button ) {
* @protected
* @param {jQuery.Event} e Mouse down event
*/
-OO.ui.ButtonElement.prototype.onMouseDown = function ( e ) {
+OO.ui.mixin.ButtonElement.prototype.onMouseDown = function ( e ) {
if ( this.isDisabled() || e.which !== 1 ) {
return;
}
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 remove the pressed class
- this.getElementDocument().addEventListener( 'mouseup', this.onMouseUpHandler, true );
+ OO.ui.addCaptureEventListener( this.getElementDocument(), 'mouseup', this.onMouseUpHandler );
// Prevent change of focus unless specifically configured otherwise
if ( this.constructor.static.cancelButtonMouseDownEvents ) {
return false;
@@ -4169,13 +4527,13 @@ OO.ui.ButtonElement.prototype.onMouseDown = function ( e ) {
* @protected
* @param {jQuery.Event} e Mouse up event
*/
-OO.ui.ButtonElement.prototype.onMouseUp = function ( e ) {
+OO.ui.mixin.ButtonElement.prototype.onMouseUp = function ( e ) {
if ( this.isDisabled() || e.which !== 1 ) {
return;
}
this.$element.removeClass( 'oo-ui-buttonElement-pressed' );
// Stop listening for mouseup, since we only needed this once
- this.getElementDocument().removeEventListener( 'mouseup', this.onMouseUpHandler, true );
+ OO.ui.removeCaptureEventListener( this.getElementDocument(), 'mouseup', this.onMouseUpHandler );
};
/**
@@ -4185,7 +4543,7 @@ OO.ui.ButtonElement.prototype.onMouseUp = function ( e ) {
* @param {jQuery.Event} e Mouse click event
* @fires click
*/
-OO.ui.ButtonElement.prototype.onClick = function ( e ) {
+OO.ui.mixin.ButtonElement.prototype.onClick = function ( e ) {
if ( !this.isDisabled() && e.which === 1 ) {
if ( this.emit( 'click' ) ) {
return false;
@@ -4199,14 +4557,14 @@ OO.ui.ButtonElement.prototype.onClick = function ( e ) {
* @protected
* @param {jQuery.Event} e Key down event
*/
-OO.ui.ButtonElement.prototype.onKeyDown = function ( e ) {
+OO.ui.mixin.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 );
+ OO.ui.addCaptureEventListener( this.getElementDocument(), 'keyup', this.onKeyUpHandler );
};
/**
@@ -4215,13 +4573,13 @@ OO.ui.ButtonElement.prototype.onKeyDown = function ( e ) {
* @protected
* @param {jQuery.Event} e Key up event
*/
-OO.ui.ButtonElement.prototype.onKeyUp = function ( e ) {
+OO.ui.mixin.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 );
+ OO.ui.removeCaptureEventListener( this.getElementDocument(), 'keyup', this.onKeyUpHandler );
};
/**
@@ -4231,7 +4589,7 @@ OO.ui.ButtonElement.prototype.onKeyUp = function ( e ) {
* @param {jQuery.Event} e Key press event
* @fires click
*/
-OO.ui.ButtonElement.prototype.onKeyPress = function ( e ) {
+OO.ui.mixin.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;
@@ -4244,7 +4602,7 @@ OO.ui.ButtonElement.prototype.onKeyPress = function ( e ) {
*
* @return {boolean} Button is framed
*/
-OO.ui.ButtonElement.prototype.isFramed = function () {
+OO.ui.mixin.ButtonElement.prototype.isFramed = function () {
return this.framed;
};
@@ -4254,7 +4612,7 @@ OO.ui.ButtonElement.prototype.isFramed = function () {
* @param {boolean} [framed] Make button framed, omit to toggle
* @chainable
*/
-OO.ui.ButtonElement.prototype.toggleFramed = function ( framed ) {
+OO.ui.mixin.ButtonElement.prototype.toggleFramed = function ( framed ) {
framed = framed === undefined ? !this.framed : !!framed;
if ( framed !== this.framed ) {
this.framed = framed;
@@ -4268,41 +4626,28 @@ OO.ui.ButtonElement.prototype.toggleFramed = function ( framed ) {
};
/**
- * Set the button's access key.
+ * Set the button's 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 {string} accessKey Button's access key, use empty string to remove
+ * @param {boolean} value Make button active
* @chainable
*/
-OO.ui.ButtonElement.prototype.setAccessKey = function ( accessKey ) {
- accessKey = typeof accessKey === 'string' && accessKey.length ? accessKey : null;
-
- if ( this.accessKey !== accessKey ) {
- if ( this.$button ) {
- if ( accessKey !== null ) {
- this.$button.attr( 'accesskey', accessKey );
- } else {
- this.$button.removeAttr( 'accesskey' );
- }
- }
- this.accessKey = accessKey;
- }
-
+OO.ui.mixin.ButtonElement.prototype.setActive = function ( value ) {
+ this.active = !!value;
+ this.$element.toggleClass( 'oo-ui-buttonElement-active', this.active );
return this;
};
/**
- * 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.
+ * Check if the button is active
*
- * @param {boolean} [value] Make button active
- * @chainable
+ * @return {boolean} The button is active
*/
-OO.ui.ButtonElement.prototype.setActive = function ( value ) {
- this.$element.toggleClass( 'oo-ui-buttonElement-active', !!value );
- return this;
+OO.ui.mixin.ButtonElement.prototype.isActive = function () {
+ return this.active;
};
/**
@@ -4321,7 +4666,7 @@ OO.ui.ButtonElement.prototype.setActive = function ( value ) {
* @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 ) {
+OO.ui.mixin.GroupElement = function OoUiMixinGroupElement( config ) {
// Configuration initialization
config = config || {};
@@ -4343,7 +4688,7 @@ OO.ui.GroupElement = function OoUiGroupElement( config ) {
*
* @param {jQuery} $group Element to use as group
*/
-OO.ui.GroupElement.prototype.setGroupElement = function ( $group ) {
+OO.ui.mixin.GroupElement.prototype.setGroupElement = function ( $group ) {
var i, len;
this.$group = $group;
@@ -4357,7 +4702,7 @@ OO.ui.GroupElement.prototype.setGroupElement = function ( $group ) {
*
* @return {boolean} Group is empty
*/
-OO.ui.GroupElement.prototype.isEmpty = function () {
+OO.ui.mixin.GroupElement.prototype.isEmpty = function () {
return !this.items.length;
};
@@ -4370,7 +4715,7 @@ OO.ui.GroupElement.prototype.isEmpty = function () {
*
* @return {OO.ui.Element[]} An array of items.
*/
-OO.ui.GroupElement.prototype.getItems = function () {
+OO.ui.mixin.GroupElement.prototype.getItems = function () {
return this.items.slice( 0 );
};
@@ -4383,7 +4728,7 @@ OO.ui.GroupElement.prototype.getItems = function () {
* @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 ) {
+OO.ui.mixin.GroupElement.prototype.getItemFromData = function ( data ) {
var i, len, item,
hash = OO.getHash( data );
@@ -4405,7 +4750,7 @@ OO.ui.GroupElement.prototype.getItemFromData = function ( data ) {
* @param {Object} data Item data to search for
* @return {OO.ui.Element[]} Items with equivalent data
*/
-OO.ui.GroupElement.prototype.getItemsFromData = function ( data ) {
+OO.ui.mixin.GroupElement.prototype.getItemsFromData = function ( data ) {
var i, len, item,
hash = OO.getHash( data ),
items = [];
@@ -4434,7 +4779,7 @@ OO.ui.GroupElement.prototype.getItemsFromData = function ( data ) {
* @throws {Error} An error is thrown if aggregation already exists.
*/
-OO.ui.GroupElement.prototype.aggregate = function ( events ) {
+OO.ui.mixin.GroupElement.prototype.aggregate = function ( events ) {
var i, len, item, add, remove, itemEvent, groupEvent;
for ( itemEvent in events ) {
@@ -4451,7 +4796,7 @@ OO.ui.GroupElement.prototype.aggregate = function ( events ) {
item = this.items[ i ];
if ( item.connect && item.disconnect ) {
remove = {};
- remove[ itemEvent ] = [ 'emit', groupEvent, item ];
+ remove[ itemEvent ] = [ 'emit', this.aggregateItemEvents[ itemEvent ], item ];
item.disconnect( this, remove );
}
}
@@ -4486,7 +4831,7 @@ OO.ui.GroupElement.prototype.aggregate = function ( events ) {
* @param {number} [index] Index of the insertion point
* @chainable
*/
-OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
+OO.ui.mixin.GroupElement.prototype.addItems = function ( items, index ) {
var i, len, item, event, events, currentIndex,
itemElements = [];
@@ -4494,7 +4839,7 @@ OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
item = items[ i ];
// Check if item exists then remove it first, effectively "moving" it
- currentIndex = $.inArray( item, this.items );
+ currentIndex = this.items.indexOf( item );
if ( currentIndex >= 0 ) {
this.removeItems( [ item ] );
// Adjust index to compensate for removal
@@ -4537,13 +4882,13 @@ OO.ui.GroupElement.prototype.addItems = function ( items, index ) {
* @param {OO.ui.Element[]} items An array of items to remove
* @chainable
*/
-OO.ui.GroupElement.prototype.removeItems = function ( items ) {
+OO.ui.mixin.GroupElement.prototype.removeItems = function ( items ) {
var i, len, item, index, remove, itemEvent;
// Remove specific items
for ( i = 0, len = items.length; i < len; i++ ) {
item = items[ i ];
- index = $.inArray( item, this.items );
+ index = this.items.indexOf( item );
if ( index !== -1 ) {
if (
item.connect && item.disconnect &&
@@ -4572,7 +4917,7 @@ OO.ui.GroupElement.prototype.removeItems = function ( items ) {
*
* @chainable
*/
-OO.ui.GroupElement.prototype.clearItems = function () {
+OO.ui.mixin.GroupElement.prototype.clearItems = function () {
var i, len, item, remove, itemEvent;
// Remove all items
@@ -4599,7 +4944,7 @@ OO.ui.GroupElement.prototype.clearItems = function () {
/**
* 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
+ * in conjunction with OO.ui.mixin.DraggableGroupElement, which provides a container for
* the draggable elements.
*
* @abstract
@@ -4607,7 +4952,7 @@ OO.ui.GroupElement.prototype.clearItems = function () {
*
* @constructor
*/
-OO.ui.DraggableElement = function OoUiDraggableElement() {
+OO.ui.mixin.DraggableElement = function OoUiMixinDraggableElement() {
// Properties
this.index = null;
@@ -4623,7 +4968,7 @@ OO.ui.DraggableElement = function OoUiDraggableElement() {
} );
};
-OO.initClass( OO.ui.DraggableElement );
+OO.initClass( OO.ui.mixin.DraggableElement );
/* Events */
@@ -4631,7 +4976,7 @@ OO.initClass( OO.ui.DraggableElement );
* @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.
+ * @param {OO.ui.mixin.DraggableElement} item The item the user has clicked and is dragging with the mouse.
*/
/**
@@ -4649,9 +4994,9 @@ OO.initClass( OO.ui.DraggableElement );
/* Static Properties */
/**
- * @inheritdoc OO.ui.ButtonElement
+ * @inheritdoc OO.ui.mixin.ButtonElement
*/
-OO.ui.DraggableElement.static.cancelButtonMouseDownEvents = false;
+OO.ui.mixin.DraggableElement.static.cancelButtonMouseDownEvents = false;
/* Methods */
@@ -4662,18 +5007,18 @@ OO.ui.DraggableElement.static.cancelButtonMouseDownEvents = false;
* @param {jQuery.Event} event jQuery event
* @fires dragstart
*/
-OO.ui.DraggableElement.prototype.onDragStart = function ( e ) {
+OO.ui.mixin.DraggableElement.prototype.onDragStart = function ( e ) {
var dataTransfer = e.originalEvent.dataTransfer;
// Define drop effect
dataTransfer.dropEffect = 'none';
dataTransfer.effectAllowed = 'move';
+ // Support: Firefox
// 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.
+ // The above is only for Firefox. Move on if it fails.
}
// Add dragging class
this.$element.addClass( 'oo-ui-draggableElement-dragging' );
@@ -4688,7 +5033,7 @@ OO.ui.DraggableElement.prototype.onDragStart = function ( e ) {
* @private
* @fires dragend
*/
-OO.ui.DraggableElement.prototype.onDragEnd = function () {
+OO.ui.mixin.DraggableElement.prototype.onDragEnd = function () {
this.$element.removeClass( 'oo-ui-draggableElement-dragging' );
this.emit( 'dragend' );
};
@@ -4700,7 +5045,7 @@ OO.ui.DraggableElement.prototype.onDragEnd = function () {
* @param {jQuery.Event} event jQuery event
* @fires drop
*/
-OO.ui.DraggableElement.prototype.onDrop = function ( e ) {
+OO.ui.mixin.DraggableElement.prototype.onDrop = function ( e ) {
e.preventDefault();
this.emit( 'drop', e );
};
@@ -4711,7 +5056,7 @@ OO.ui.DraggableElement.prototype.onDrop = function ( e ) {
*
* @private
*/
-OO.ui.DraggableElement.prototype.onDragOver = function ( e ) {
+OO.ui.mixin.DraggableElement.prototype.onDragOver = function ( e ) {
e.preventDefault();
};
@@ -4722,7 +5067,7 @@ OO.ui.DraggableElement.prototype.onDragOver = function ( e ) {
* @private
* @param {number} Item index
*/
-OO.ui.DraggableElement.prototype.setIndex = function ( index ) {
+OO.ui.mixin.DraggableElement.prototype.setIndex = function ( index ) {
if ( this.index !== index ) {
this.index = index;
this.$element.data( 'index', index );
@@ -4735,18 +5080,18 @@ OO.ui.DraggableElement.prototype.setIndex = function ( index ) {
* @private
* @return {number} Item index
*/
-OO.ui.DraggableElement.prototype.getIndex = function () {
+OO.ui.mixin.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.
+ * The class is used with OO.ui.mixin.DraggableElement.
*
* @abstract
* @class
- * @mixins OO.ui.GroupElement
+ * @mixins OO.ui.mixin.GroupElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -4755,12 +5100,12 @@ OO.ui.DraggableElement.prototype.getIndex = function () {
* 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 ) {
+OO.ui.mixin.DraggableGroupElement = function OoUiMixinDraggableGroupElement( config ) {
// Configuration initialization
config = config || {};
// Parent constructor
- OO.ui.GroupElement.call( this, config );
+ OO.ui.mixin.GroupElement.call( this, config );
// Properties
this.orientation = config.orientation || 'vertical';
@@ -4781,8 +5126,8 @@ OO.ui.DraggableGroupElement = function OoUiDraggableGroupElement( config ) {
itemDragEnd: 'onItemDragEnd'
} );
this.$element.on( {
- dragover: $.proxy( this.onDragOver, this ),
- dragleave: $.proxy( this.onDragLeave, this )
+ dragover: this.onDragOver.bind( this ),
+ dragleave: this.onDragLeave.bind( this )
} );
// Initialize
@@ -4799,7 +5144,7 @@ OO.ui.DraggableGroupElement = function OoUiDraggableGroupElement( config ) {
};
/* Setup */
-OO.mixinClass( OO.ui.DraggableGroupElement, OO.ui.GroupElement );
+OO.mixinClass( OO.ui.mixin.DraggableGroupElement, OO.ui.mixin.GroupElement );
/* Events */
@@ -4807,7 +5152,7 @@ OO.mixinClass( OO.ui.DraggableGroupElement, OO.ui.GroupElement );
* A 'reorder' event is emitted when the order of items in the group changes.
*
* @event reorder
- * @param {OO.ui.DraggableElement} item Reordered item
+ * @param {OO.ui.mixin.DraggableElement} item Reordered item
* @param {number} [newIndex] New index for the item
*/
@@ -4817,9 +5162,9 @@ OO.mixinClass( OO.ui.DraggableGroupElement, OO.ui.GroupElement );
* Respond to item drag start event
*
* @private
- * @param {OO.ui.DraggableElement} item Dragged item
+ * @param {OO.ui.mixin.DraggableElement} item Dragged item
*/
-OO.ui.DraggableGroupElement.prototype.onItemDragStart = function ( item ) {
+OO.ui.mixin.DraggableGroupElement.prototype.onItemDragStart = function ( item ) {
var i, len;
// Map the index of each object
@@ -4848,7 +5193,7 @@ OO.ui.DraggableGroupElement.prototype.onItemDragStart = function ( item ) {
*
* @private
*/
-OO.ui.DraggableGroupElement.prototype.onItemDragEnd = function () {
+OO.ui.mixin.DraggableGroupElement.prototype.onItemDragEnd = function () {
this.unsetDragItem();
return false;
};
@@ -4857,10 +5202,10 @@ OO.ui.DraggableGroupElement.prototype.onItemDragEnd = function () {
* Handle drop event and switch the order of the items accordingly
*
* @private
- * @param {OO.ui.DraggableElement} item Dropped item
+ * @param {OO.ui.mixin.DraggableElement} item Dropped item
* @fires reorder
*/
-OO.ui.DraggableGroupElement.prototype.onItemDrop = function ( item ) {
+OO.ui.mixin.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
@@ -4884,7 +5229,7 @@ OO.ui.DraggableGroupElement.prototype.onItemDrop = function ( item ) {
*
* @private
*/
-OO.ui.DraggableGroupElement.prototype.onDragLeave = function () {
+OO.ui.mixin.DraggableGroupElement.prototype.onDragLeave = function () {
// This means the item was dragged outside the widget
this.$placeholder
.css( 'left', 0 )
@@ -4897,7 +5242,7 @@ OO.ui.DraggableGroupElement.prototype.onDragLeave = function () {
* @private
* @param {jQuery.Event} event Event details
*/
-OO.ui.DraggableGroupElement.prototype.onDragOver = function ( e ) {
+OO.ui.mixin.DraggableGroupElement.prototype.onDragOver = function ( e ) {
var dragOverObj, $optionWidget, itemOffset, itemMidpoint, itemBoundingRect,
itemSize, cssOutput, dragPosition, itemIndex, itemPosition,
clientX = e.originalEvent.clientX,
@@ -4967,16 +5312,16 @@ OO.ui.DraggableGroupElement.prototype.onDragOver = function ( e ) {
/**
* Set a dragged item
*
- * @param {OO.ui.DraggableElement} item Dragged item
+ * @param {OO.ui.mixin.DraggableElement} item Dragged item
*/
-OO.ui.DraggableGroupElement.prototype.setDragItem = function ( item ) {
+OO.ui.mixin.DraggableGroupElement.prototype.setDragItem = function ( item ) {
this.dragItem = item;
};
/**
* Unset the current dragged item
*/
-OO.ui.DraggableGroupElement.prototype.unsetDragItem = function () {
+OO.ui.mixin.DraggableGroupElement.prototype.unsetDragItem = function () {
this.dragItem = null;
this.itemDragOver = null;
this.$placeholder.addClass( 'oo-ui-element-hidden' );
@@ -4986,9 +5331,9 @@ OO.ui.DraggableGroupElement.prototype.unsetDragItem = function () {
/**
* 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
+ * @return {OO.ui.mixin.DraggableElement|null} The currently dragged item, or `null` if no item is being dragged
*/
-OO.ui.DraggableGroupElement.prototype.getDragItem = function () {
+OO.ui.mixin.DraggableGroupElement.prototype.getDragItem = function () {
return this.dragItem;
};
@@ -4997,7 +5342,7 @@ OO.ui.DraggableGroupElement.prototype.getDragItem = function () {
*
* @return {Boolean} Item is being dragged
*/
-OO.ui.DraggableGroupElement.prototype.isDragging = function () {
+OO.ui.mixin.DraggableGroupElement.prototype.isDragging = function () {
return this.getDragItem() !== null;
};
@@ -5039,7 +5384,7 @@ OO.ui.DraggableGroupElement.prototype.isDragging = function () {
* @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 ) {
+OO.ui.mixin.IconElement = function OoUiMixinIconElement( config ) {
// Configuration initialization
config = config || {};
@@ -5056,7 +5401,7 @@ OO.ui.IconElement = function OoUiIconElement( config ) {
/* Setup */
-OO.initClass( OO.ui.IconElement );
+OO.initClass( OO.ui.mixin.IconElement );
/* Static Properties */
@@ -5075,7 +5420,7 @@ OO.initClass( OO.ui.IconElement );
* @inheritable
* @property {Object|string}
*/
-OO.ui.IconElement.static.icon = null;
+OO.ui.mixin.IconElement.static.icon = null;
/**
* The icon title, displayed when users move the mouse over the icon. The value can be text, a
@@ -5087,7 +5432,7 @@ OO.ui.IconElement.static.icon = null;
* @inheritable
* @property {string|Function|null}
*/
-OO.ui.IconElement.static.iconTitle = null;
+OO.ui.mixin.IconElement.static.iconTitle = null;
/* Methods */
@@ -5099,7 +5444,7 @@ OO.ui.IconElement.static.iconTitle = null;
*
* @param {jQuery} $icon Element to use as icon
*/
-OO.ui.IconElement.prototype.setIconElement = function ( $icon ) {
+OO.ui.mixin.IconElement.prototype.setIconElement = function ( $icon ) {
if ( this.$icon ) {
this.$icon
.removeClass( 'oo-ui-iconElement-icon oo-ui-icon-' + this.icon )
@@ -5112,6 +5457,8 @@ OO.ui.IconElement.prototype.setIconElement = function ( $icon ) {
if ( this.iconTitle !== null ) {
this.$icon.attr( 'title', this.iconTitle );
}
+
+ this.updateThemeClasses();
};
/**
@@ -5123,7 +5470,7 @@ OO.ui.IconElement.prototype.setIconElement = function ( $icon ) {
* by language code, or `null` to remove the icon.
* @chainable
*/
-OO.ui.IconElement.prototype.setIcon = function ( icon ) {
+OO.ui.mixin.IconElement.prototype.setIcon = function ( icon ) {
icon = OO.isPlainObject( icon ) ? OO.ui.getLocalValue( icon, null, 'default' ) : icon;
icon = typeof icon === 'string' && icon.trim().length ? icon.trim() : null;
@@ -5152,7 +5499,7 @@ OO.ui.IconElement.prototype.setIcon = function ( icon ) {
* a function that returns title text, or `null` for no title.
* @chainable
*/
-OO.ui.IconElement.prototype.setIconTitle = function ( iconTitle ) {
+OO.ui.mixin.IconElement.prototype.setIconTitle = function ( iconTitle ) {
iconTitle = typeof iconTitle === 'function' ||
( typeof iconTitle === 'string' && iconTitle.length ) ?
OO.ui.resolveMsg( iconTitle ) : null;
@@ -5176,7 +5523,7 @@ OO.ui.IconElement.prototype.setIconTitle = function ( iconTitle ) {
*
* @return {string} Icon name
*/
-OO.ui.IconElement.prototype.getIcon = function () {
+OO.ui.mixin.IconElement.prototype.getIcon = function () {
return this.icon;
};
@@ -5185,7 +5532,7 @@ OO.ui.IconElement.prototype.getIcon = function () {
*
* @return {string} Icon title text
*/
-OO.ui.IconElement.prototype.getIconTitle = function () {
+OO.ui.mixin.IconElement.prototype.getIconTitle = function () {
return this.iconTitle;
};
@@ -5218,7 +5565,7 @@ OO.ui.IconElement.prototype.getIconTitle = function () {
* 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 ) {
+OO.ui.mixin.IndicatorElement = function OoUiMixinIndicatorElement( config ) {
// Configuration initialization
config = config || {};
@@ -5235,7 +5582,7 @@ OO.ui.IndicatorElement = function OoUiIndicatorElement( config ) {
/* Setup */
-OO.initClass( OO.ui.IndicatorElement );
+OO.initClass( OO.ui.mixin.IndicatorElement );
/* Static Properties */
@@ -5247,7 +5594,7 @@ OO.initClass( OO.ui.IndicatorElement );
* @inheritable
* @property {string|null}
*/
-OO.ui.IndicatorElement.static.indicator = null;
+OO.ui.mixin.IndicatorElement.static.indicator = null;
/**
* A text string used as the indicator title, a function that returns title text, or `null`
@@ -5257,7 +5604,7 @@ OO.ui.IndicatorElement.static.indicator = null;
* @inheritable
* @property {string|Function|null}
*/
-OO.ui.IndicatorElement.static.indicatorTitle = null;
+OO.ui.mixin.IndicatorElement.static.indicatorTitle = null;
/* Methods */
@@ -5268,7 +5615,7 @@ OO.ui.IndicatorElement.static.indicatorTitle = null;
*
* @param {jQuery} $indicator Element to use as indicator
*/
-OO.ui.IndicatorElement.prototype.setIndicatorElement = function ( $indicator ) {
+OO.ui.mixin.IndicatorElement.prototype.setIndicatorElement = function ( $indicator ) {
if ( this.$indicator ) {
this.$indicator
.removeClass( 'oo-ui-indicatorElement-indicator oo-ui-indicator-' + this.indicator )
@@ -5281,6 +5628,8 @@ OO.ui.IndicatorElement.prototype.setIndicatorElement = function ( $indicator ) {
if ( this.indicatorTitle !== null ) {
this.$indicator.attr( 'title', this.indicatorTitle );
}
+
+ this.updateThemeClasses();
};
/**
@@ -5289,7 +5638,7 @@ OO.ui.IndicatorElement.prototype.setIndicatorElement = function ( $indicator ) {
* @param {string|null} indicator Symbolic name of indicator, or `null` for no indicator
* @chainable
*/
-OO.ui.IndicatorElement.prototype.setIndicator = function ( indicator ) {
+OO.ui.mixin.IndicatorElement.prototype.setIndicator = function ( indicator ) {
indicator = typeof indicator === 'string' && indicator.length ? indicator.trim() : null;
if ( this.indicator !== indicator ) {
@@ -5319,7 +5668,7 @@ OO.ui.IndicatorElement.prototype.setIndicator = function ( indicator ) {
* `null` for no indicator title
* @chainable
*/
-OO.ui.IndicatorElement.prototype.setIndicatorTitle = function ( indicatorTitle ) {
+OO.ui.mixin.IndicatorElement.prototype.setIndicatorTitle = function ( indicatorTitle ) {
indicatorTitle = typeof indicatorTitle === 'function' ||
( typeof indicatorTitle === 'string' && indicatorTitle.length ) ?
OO.ui.resolveMsg( indicatorTitle ) : null;
@@ -5343,7 +5692,7 @@ OO.ui.IndicatorElement.prototype.setIndicatorTitle = function ( indicatorTitle )
*
* @return {string} Symbolic name of indicator
*/
-OO.ui.IndicatorElement.prototype.getIndicator = function () {
+OO.ui.mixin.IndicatorElement.prototype.getIndicator = function () {
return this.indicator;
};
@@ -5354,7 +5703,7 @@ OO.ui.IndicatorElement.prototype.getIndicator = function () {
*
* @return {string} Indicator title text
*/
-OO.ui.IndicatorElement.prototype.getIndicatorTitle = function () {
+OO.ui.mixin.IndicatorElement.prototype.getIndicatorTitle = function () {
return this.indicatorTitle;
};
@@ -5379,7 +5728,7 @@ OO.ui.IndicatorElement.prototype.getIndicatorTitle = function () {
* @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 ) {
+OO.ui.mixin.LabelElement = function OoUiMixinLabelElement( config ) {
// Configuration initialization
config = config || {};
@@ -5395,7 +5744,7 @@ OO.ui.LabelElement = function OoUiLabelElement( config ) {
/* Setup */
-OO.initClass( OO.ui.LabelElement );
+OO.initClass( OO.ui.mixin.LabelElement );
/* Events */
@@ -5415,7 +5764,7 @@ OO.initClass( OO.ui.LabelElement );
* @inheritable
* @property {string|Function|null}
*/
-OO.ui.LabelElement.static.label = null;
+OO.ui.mixin.LabelElement.static.label = null;
/* Methods */
@@ -5426,7 +5775,7 @@ OO.ui.LabelElement.static.label = null;
*
* @param {jQuery} $label Element to use as label
*/
-OO.ui.LabelElement.prototype.setLabelElement = function ( $label ) {
+OO.ui.mixin.LabelElement.prototype.setLabelElement = function ( $label ) {
if ( this.$label ) {
this.$label.removeClass( 'oo-ui-labelElement-label' ).empty();
}
@@ -5445,7 +5794,7 @@ OO.ui.LabelElement.prototype.setLabelElement = function ( $label ) {
* text; or null for no label
* @chainable
*/
-OO.ui.LabelElement.prototype.setLabel = function ( label ) {
+OO.ui.mixin.LabelElement.prototype.setLabel = function ( label ) {
label = typeof label === 'function' ? OO.ui.resolveMsg( label ) : label;
label = ( ( typeof label === 'string' && label.length ) || label instanceof jQuery || label instanceof OO.ui.HtmlSnippet ) ? label : null;
@@ -5468,7 +5817,7 @@ OO.ui.LabelElement.prototype.setLabel = function ( label ) {
* @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 () {
+OO.ui.mixin.LabelElement.prototype.getLabel = function () {
return this.label;
};
@@ -5477,7 +5826,7 @@ OO.ui.LabelElement.prototype.getLabel = function () {
*
* @chainable
*/
-OO.ui.LabelElement.prototype.fitLabel = function () {
+OO.ui.mixin.LabelElement.prototype.fitLabel = function () {
if ( this.$label && this.$label.autoEllipsis && this.autoFitLabel ) {
this.$label.autoEllipsis( { hasSpan: false, tooltip: true } );
}
@@ -5494,7 +5843,7 @@ OO.ui.LabelElement.prototype.fitLabel = function () {
* @param {jQuery|string|Function|null} label Label nodes; text; a function that returns nodes or
* text; or null for no label
*/
-OO.ui.LabelElement.prototype.setLabelContent = function ( label ) {
+OO.ui.mixin.LabelElement.prototype.setLabelContent = function ( label ) {
if ( typeof label === 'string' ) {
if ( label.match( /^\s*$/ ) ) {
// Convert whitespace only string to a single non-breaking space
@@ -5512,7 +5861,7 @@ OO.ui.LabelElement.prototype.setLabelContent = function ( label ) {
};
/**
- * LookupElement is a mixin that creates a {@link OO.ui.TextInputMenuSelectWidget menu} of suggested values for
+ * LookupElement is a mixin that creates a {@link OO.ui.FloatingMenuSelectWidget 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.
@@ -5535,16 +5884,16 @@ OO.ui.LabelElement.prototype.setLabelContent = function ( label ) {
* @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 ) {
+OO.ui.mixin.LookupElement = function OoUiMixinLookupElement( config ) {
// Configuration initialization
config = config || {};
// Properties
this.$overlay = config.$overlay || this.$element;
- this.lookupMenu = new OO.ui.TextInputMenuSelectWidget( this, {
+ this.lookupMenu = new OO.ui.FloatingMenuSelectWidget( {
widget: this,
input: this,
- $container: config.$container
+ $container: config.$container || this.$element
} );
this.allowSuggestionsWhenEmpty = config.allowSuggestionsWhenEmpty || false;
@@ -5581,7 +5930,7 @@ OO.ui.LookupElement = function OoUiLookupElement( config ) {
* @protected
* @param {jQuery.Event} e Input focus event
*/
-OO.ui.LookupElement.prototype.onLookupInputFocus = function () {
+OO.ui.mixin.LookupElement.prototype.onLookupInputFocus = function () {
this.lookupInputFocused = true;
this.populateLookupMenu();
};
@@ -5592,7 +5941,7 @@ OO.ui.LookupElement.prototype.onLookupInputFocus = function () {
* @protected
* @param {jQuery.Event} e Input blur event
*/
-OO.ui.LookupElement.prototype.onLookupInputBlur = function () {
+OO.ui.mixin.LookupElement.prototype.onLookupInputBlur = function () {
this.closeLookupMenu();
this.lookupInputFocused = false;
};
@@ -5603,7 +5952,7 @@ OO.ui.LookupElement.prototype.onLookupInputBlur = function () {
* @protected
* @param {jQuery.Event} e Input mouse down event
*/
-OO.ui.LookupElement.prototype.onLookupInputMouseDown = function () {
+OO.ui.mixin.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
@@ -5619,7 +5968,7 @@ OO.ui.LookupElement.prototype.onLookupInputMouseDown = function () {
* @protected
* @param {string} value New input value
*/
-OO.ui.LookupElement.prototype.onLookupInputChange = function () {
+OO.ui.mixin.LookupElement.prototype.onLookupInputChange = function () {
if ( this.lookupInputFocused ) {
this.populateLookupMenu();
}
@@ -5631,7 +5980,7 @@ OO.ui.LookupElement.prototype.onLookupInputChange = function () {
* @protected
* @param {boolean} visible Whether the lookup menu is now visible.
*/
-OO.ui.LookupElement.prototype.onLookupMenuToggle = function ( visible ) {
+OO.ui.mixin.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
@@ -5647,7 +5996,7 @@ OO.ui.LookupElement.prototype.onLookupMenuToggle = function ( visible ) {
* @protected
* @param {OO.ui.MenuOptionWidget} item Selected item
*/
-OO.ui.LookupElement.prototype.onLookupMenuItemChoose = function ( item ) {
+OO.ui.mixin.LookupElement.prototype.onLookupMenuItemChoose = function ( item ) {
this.setValue( item.getData() );
};
@@ -5655,9 +6004,9 @@ OO.ui.LookupElement.prototype.onLookupMenuItemChoose = function ( item ) {
* Get lookup menu.
*
* @private
- * @return {OO.ui.TextInputMenuSelectWidget}
+ * @return {OO.ui.FloatingMenuSelectWidget}
*/
-OO.ui.LookupElement.prototype.getLookupMenu = function () {
+OO.ui.mixin.LookupElement.prototype.getLookupMenu = function () {
return this.lookupMenu;
};
@@ -5668,7 +6017,7 @@ OO.ui.LookupElement.prototype.getLookupMenu = function () {
*
* @param {boolean} disabled Disable lookups
*/
-OO.ui.LookupElement.prototype.setLookupsDisabled = function ( disabled ) {
+OO.ui.mixin.LookupElement.prototype.setLookupsDisabled = function ( disabled ) {
this.lookupsDisabled = !!disabled;
};
@@ -5678,7 +6027,7 @@ OO.ui.LookupElement.prototype.setLookupsDisabled = function ( disabled ) {
* @private
* @chainable
*/
-OO.ui.LookupElement.prototype.openLookupMenu = function () {
+OO.ui.mixin.LookupElement.prototype.openLookupMenu = function () {
if ( !this.lookupMenu.isEmpty() ) {
this.lookupMenu.toggle( true );
}
@@ -5691,7 +6040,7 @@ OO.ui.LookupElement.prototype.openLookupMenu = function () {
* @private
* @chainable
*/
-OO.ui.LookupElement.prototype.closeLookupMenu = function () {
+OO.ui.mixin.LookupElement.prototype.closeLookupMenu = function () {
this.lookupMenu.toggle( false );
this.abortLookupRequest();
this.lookupMenu.clearItems();
@@ -5707,11 +6056,11 @@ OO.ui.LookupElement.prototype.closeLookupMenu = function () {
* @private
* @chainable
*/
-OO.ui.LookupElement.prototype.populateLookupMenu = function () {
+OO.ui.mixin.LookupElement.prototype.populateLookupMenu = function () {
var widget = this,
value = this.getValue();
- if ( this.lookupsDisabled ) {
+ if ( this.lookupsDisabled || this.isReadOnly() ) {
return;
}
@@ -5746,7 +6095,7 @@ OO.ui.LookupElement.prototype.populateLookupMenu = function () {
* @private
* @chainable
*/
-OO.ui.LookupElement.prototype.initializeLookupMenuSelection = function () {
+OO.ui.mixin.LookupElement.prototype.initializeLookupMenuSelection = function () {
if ( !this.lookupMenu.getSelectedItem() ) {
this.lookupMenu.highlightItem( this.lookupMenu.getFirstSelectableItem() );
}
@@ -5760,7 +6109,7 @@ OO.ui.LookupElement.prototype.initializeLookupMenuSelection = function () {
* 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 () {
+OO.ui.mixin.LookupElement.prototype.getLookupMenuItems = function () {
var widget = this,
value = this.getValue(),
deferred = $.Deferred(),
@@ -5811,7 +6160,7 @@ OO.ui.LookupElement.prototype.getLookupMenuItems = function () {
*
* @private
*/
-OO.ui.LookupElement.prototype.abortLookupRequest = function () {
+OO.ui.mixin.LookupElement.prototype.abortLookupRequest = function () {
var oldRequest = this.lookupRequest;
if ( oldRequest ) {
// First unset this.lookupRequest to the fail handler will notice
@@ -5829,7 +6178,7 @@ OO.ui.LookupElement.prototype.abortLookupRequest = function () {
* @abstract
* @return {jQuery.Promise} jQuery AJAX object, or promise object with an .abort() method
*/
-OO.ui.LookupElement.prototype.getLookupRequest = function () {
+OO.ui.mixin.LookupElement.prototype.getLookupRequest = function () {
// Stub, implemented in subclass
return null;
};
@@ -5845,7 +6194,7 @@ OO.ui.LookupElement.prototype.getLookupRequest = function () {
* @param {Mixed} response Response from server
* @return {Mixed} Cached result data
*/
-OO.ui.LookupElement.prototype.getLookupCacheDataFromResponse = function () {
+OO.ui.mixin.LookupElement.prototype.getLookupCacheDataFromResponse = function () {
// Stub, implemented in subclass
return [];
};
@@ -5859,12 +6208,33 @@ OO.ui.LookupElement.prototype.getLookupCacheDataFromResponse = function () {
* @param {Mixed} data Cached result data, usually an array
* @return {OO.ui.MenuOptionWidget[]} Menu items
*/
-OO.ui.LookupElement.prototype.getLookupMenuOptionsFromData = function () {
+OO.ui.mixin.LookupElement.prototype.getLookupMenuOptionsFromData = function () {
// Stub, implemented in subclass
return [];
};
/**
+ * Set the read-only state of the widget.
+ *
+ * This will also disable/enable the lookups functionality.
+ *
+ * @param {boolean} readOnly Make input read-only
+ * @chainable
+ */
+OO.ui.mixin.LookupElement.prototype.setReadOnly = function ( readOnly ) {
+ // Parent method
+ // Note: Calling #setReadOnly this way assumes this is mixed into an OO.ui.TextInputWidget
+ OO.ui.TextInputWidget.prototype.setReadOnly.call( this, readOnly );
+
+ // During construction, #setReadOnly is called before the OO.ui.mixin.LookupElement constructor
+ if ( this.isReadOnly() && this.lookupMenu ) {
+ this.closeLookupMenu();
+ }
+
+ return this;
+};
+
+/**
* 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.
@@ -5878,7 +6248,7 @@ OO.ui.LookupElement.prototype.getLookupMenuOptionsFromData = function () {
* @cfg {Object} [popup] Configuration to pass to popup
* @cfg {boolean} [popup.autoClose=true] Popup auto-closes when it loses focus
*/
-OO.ui.PopupElement = function OoUiPopupElement( config ) {
+OO.ui.mixin.PopupElement = function OoUiMixinPopupElement( config ) {
// Configuration initialization
config = config || {};
@@ -5897,7 +6267,7 @@ OO.ui.PopupElement = function OoUiPopupElement( config ) {
*
* @return {OO.ui.PopupWidget} Popup widget
*/
-OO.ui.PopupElement.prototype.getPopup = function () {
+OO.ui.mixin.PopupElement.prototype.getPopup = function () {
return this.popup;
};
@@ -5949,7 +6319,7 @@ OO.ui.PopupElement.prototype.getPopup = function () {
* 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 ) {
+OO.ui.mixin.FlaggedElement = function OoUiMixinFlaggedElement( config ) {
// Configuration initialization
config = config || {};
@@ -5984,7 +6354,7 @@ OO.ui.FlaggedElement = function OoUiFlaggedElement( config ) {
*
* @param {jQuery} $flagged Element that should be flagged
*/
-OO.ui.FlaggedElement.prototype.setFlaggedElement = function ( $flagged ) {
+OO.ui.mixin.FlaggedElement.prototype.setFlaggedElement = function ( $flagged ) {
var classNames = Object.keys( this.flags ).map( function ( flag ) {
return 'oo-ui-flaggedElement-' + flag;
} ).join( ' ' );
@@ -6002,8 +6372,9 @@ OO.ui.FlaggedElement.prototype.setFlaggedElement = function ( $flagged ) {
* @param {string} flag Name of flag
* @return {boolean} The flag is set
*/
-OO.ui.FlaggedElement.prototype.hasFlag = function ( flag ) {
- return flag in this.flags;
+OO.ui.mixin.FlaggedElement.prototype.hasFlag = function ( flag ) {
+ // This may be called before the constructor, thus before this.flags is set
+ return this.flags && ( flag in this.flags );
};
/**
@@ -6011,8 +6382,9 @@ OO.ui.FlaggedElement.prototype.hasFlag = function ( flag ) {
*
* @return {string[]} Flag names
*/
-OO.ui.FlaggedElement.prototype.getFlags = function () {
- return Object.keys( this.flags );
+OO.ui.mixin.FlaggedElement.prototype.getFlags = function () {
+ // This may be called before the constructor, thus before this.flags is set
+ return Object.keys( this.flags || {} );
};
/**
@@ -6021,7 +6393,7 @@ OO.ui.FlaggedElement.prototype.getFlags = function () {
* @chainable
* @fires flag
*/
-OO.ui.FlaggedElement.prototype.clearFlags = function () {
+OO.ui.mixin.FlaggedElement.prototype.clearFlags = function () {
var flag, className,
changes = {},
remove = [],
@@ -6053,7 +6425,7 @@ OO.ui.FlaggedElement.prototype.clearFlags = function () {
* @chainable
* @fires flag
*/
-OO.ui.FlaggedElement.prototype.setFlags = function ( flags ) {
+OO.ui.mixin.FlaggedElement.prototype.setFlags = function ( flags ) {
var i, len, flag, className,
changes = {},
add = [],
@@ -6136,7 +6508,7 @@ OO.ui.FlaggedElement.prototype.setFlags = function ( flags ) {
* @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 ) {
+OO.ui.mixin.TitledElement = function OoUiMixinTitledElement( config ) {
// Configuration initialization
config = config || {};
@@ -6151,7 +6523,7 @@ OO.ui.TitledElement = function OoUiTitledElement( config ) {
/* Setup */
-OO.initClass( OO.ui.TitledElement );
+OO.initClass( OO.ui.mixin.TitledElement );
/* Static Properties */
@@ -6163,7 +6535,7 @@ OO.initClass( OO.ui.TitledElement );
* @inheritable
* @property {string|Function|null}
*/
-OO.ui.TitledElement.static.title = null;
+OO.ui.mixin.TitledElement.static.title = null;
/* Methods */
@@ -6175,7 +6547,7 @@ OO.ui.TitledElement.static.title = null;
*
* @param {jQuery} $titled Element that should use the 'titled' functionality
*/
-OO.ui.TitledElement.prototype.setTitledElement = function ( $titled ) {
+OO.ui.mixin.TitledElement.prototype.setTitledElement = function ( $titled ) {
if ( this.$titled ) {
this.$titled.removeAttr( 'title' );
}
@@ -6192,7 +6564,7 @@ OO.ui.TitledElement.prototype.setTitledElement = function ( $titled ) {
* @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 ) {
+OO.ui.mixin.TitledElement.prototype.setTitle = function ( title ) {
title = typeof title === 'string' ? OO.ui.resolveMsg( title ) : null;
if ( this.title !== title ) {
@@ -6214,7 +6586,7 @@ OO.ui.TitledElement.prototype.setTitle = function ( title ) {
*
* @return {string} Title string
*/
-OO.ui.TitledElement.prototype.getTitle = function () {
+OO.ui.mixin.TitledElement.prototype.getTitle = function () {
return this.title;
};
@@ -6222,33 +6594,47 @@ OO.ui.TitledElement.prototype.getTitle = function () {
* Element that can be automatically clipped to visible boundaries.
*
* Whenever the element's natural height changes, you have to call
- * #clip to make sure it's still clipping correctly.
+ * {@link OO.ui.mixin.ClippableElement#clip} to make sure it's still
+ * clipping correctly.
+ *
+ * The dimensions of #$clippableContainer will be compared to the boundaries of the
+ * nearest scrollable container. If #$clippableContainer is too tall and/or too wide,
+ * then #$clippable will be given a fixed reduced height and/or width and will be made
+ * scrollable. By default, #$clippable and #$clippableContainer are the same element,
+ * but you can build a static footer by setting #$clippableContainer to an element that contains
+ * #$clippable and the footer.
*
* @abstract
* @class
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {jQuery} [$clippable] Nodes to clip, assigned to #$clippable, omit to use #$element
+ * @cfg {jQuery} [$clippable] Node to clip, assigned to #$clippable, omit to use #$element
+ * @cfg {jQuery} [$clippableContainer] Node to keep visible, assigned to #$clippableContainer,
+ * omit to use #$clippable
*/
-OO.ui.ClippableElement = function OoUiClippableElement( config ) {
+OO.ui.mixin.ClippableElement = function OoUiMixinClippableElement( config ) {
// Configuration initialization
config = config || {};
// Properties
this.$clippable = null;
+ this.$clippableContainer = null;
this.clipping = false;
this.clippedHorizontally = false;
this.clippedVertically = false;
- this.$clippableContainer = null;
+ this.$clippableScrollableContainer = null;
this.$clippableScroller = null;
this.$clippableWindow = null;
this.idealWidth = null;
this.idealHeight = null;
- this.onClippableContainerScrollHandler = this.clip.bind( this );
+ this.onClippableScrollHandler = this.clip.bind( this );
this.onClippableWindowResizeHandler = this.clip.bind( this );
// Initialization
+ if ( config.$clippableContainer ) {
+ this.setClippableContainer( config.$clippableContainer );
+ }
this.setClippableElement( config.$clippable || this.$element );
};
@@ -6261,7 +6647,7 @@ OO.ui.ClippableElement = function OoUiClippableElement( config ) {
*
* @param {jQuery} $clippable Element to make clippable
*/
-OO.ui.ClippableElement.prototype.setClippableElement = function ( $clippable ) {
+OO.ui.mixin.ClippableElement.prototype.setClippableElement = function ( $clippable ) {
if ( this.$clippable ) {
this.$clippable.removeClass( 'oo-ui-clippableElement-clippable' );
this.$clippable.css( { width: '', height: '', overflowX: '', overflowY: '' } );
@@ -6273,6 +6659,23 @@ OO.ui.ClippableElement.prototype.setClippableElement = function ( $clippable ) {
};
/**
+ * Set clippable container.
+ *
+ * This is the container that will be measured when deciding whether to clip. When clipping,
+ * #$clippable will be resized in order to keep the clippable container fully visible.
+ *
+ * If the clippable container is unset, #$clippable will be used.
+ *
+ * @param {jQuery|null} $clippableContainer Container to keep visible, or null to unset
+ */
+OO.ui.mixin.ClippableElement.prototype.setClippableContainer = function ( $clippableContainer ) {
+ this.$clippableContainer = $clippableContainer;
+ if ( this.$clippable ) {
+ this.clip();
+ }
+};
+
+/**
* Toggle clipping.
*
* Do not turn clipping on until after the element is attached to the DOM and visible.
@@ -6280,19 +6683,19 @@ OO.ui.ClippableElement.prototype.setClippableElement = function ( $clippable ) {
* @param {boolean} [clipping] Enable clipping, omit to toggle
* @chainable
*/
-OO.ui.ClippableElement.prototype.toggleClipping = function ( clipping ) {
+OO.ui.mixin.ClippableElement.prototype.toggleClipping = function ( clipping ) {
clipping = clipping === undefined ? !this.clipping : !!clipping;
if ( this.clipping !== clipping ) {
this.clipping = clipping;
if ( clipping ) {
- this.$clippableContainer = $( this.getClosestScrollableElementContainer() );
+ this.$clippableScrollableContainer = $( 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( 'html, body' ) ?
- $( OO.ui.Element.static.getWindow( this.$clippableContainer ) ) :
- this.$clippableContainer;
- this.$clippableScroller.on( 'scroll', this.onClippableContainerScrollHandler );
+ this.$clippableScroller = this.$clippableScrollableContainer.is( 'html, body' ) ?
+ $( OO.ui.Element.static.getWindow( this.$clippableScrollableContainer ) ) :
+ this.$clippableScrollableContainer;
+ this.$clippableScroller.on( 'scroll', this.onClippableScrollHandler );
this.$clippableWindow = $( this.getElementWindow() )
.on( 'resize', this.onClippableWindowResizeHandler );
// Initial clip after visible
@@ -6301,8 +6704,8 @@ OO.ui.ClippableElement.prototype.toggleClipping = function ( clipping ) {
this.$clippable.css( { width: '', height: '', overflowX: '', overflowY: '' } );
OO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );
- this.$clippableContainer = null;
- this.$clippableScroller.off( 'scroll', this.onClippableContainerScrollHandler );
+ this.$clippableScrollableContainer = null;
+ this.$clippableScroller.off( 'scroll', this.onClippableScrollHandler );
this.$clippableScroller = null;
this.$clippableWindow.off( 'resize', this.onClippableWindowResizeHandler );
this.$clippableWindow = null;
@@ -6317,7 +6720,7 @@ OO.ui.ClippableElement.prototype.toggleClipping = function ( clipping ) {
*
* @return {boolean} Element will be clipped to the visible area
*/
-OO.ui.ClippableElement.prototype.isClipping = function () {
+OO.ui.mixin.ClippableElement.prototype.isClipping = function () {
return this.clipping;
};
@@ -6326,7 +6729,7 @@ OO.ui.ClippableElement.prototype.isClipping = function () {
*
* @return {boolean} Part of the element is being clipped
*/
-OO.ui.ClippableElement.prototype.isClipped = function () {
+OO.ui.mixin.ClippableElement.prototype.isClipped = function () {
return this.clippedHorizontally || this.clippedVertically;
};
@@ -6335,7 +6738,7 @@ OO.ui.ClippableElement.prototype.isClipped = function () {
*
* @return {boolean} Part of the element is being clipped
*/
-OO.ui.ClippableElement.prototype.isClippedHorizontally = function () {
+OO.ui.mixin.ClippableElement.prototype.isClippedHorizontally = function () {
return this.clippedHorizontally;
};
@@ -6344,7 +6747,7 @@ OO.ui.ClippableElement.prototype.isClippedHorizontally = function () {
*
* @return {boolean} Part of the element is being clipped
*/
-OO.ui.ClippableElement.prototype.isClippedVertically = function () {
+OO.ui.mixin.ClippableElement.prototype.isClippedVertically = function () {
return this.clippedVertically;
};
@@ -6354,7 +6757,7 @@ OO.ui.ClippableElement.prototype.isClippedVertically = function () {
* @param {number|string} [width] Width as a number of pixels or CSS string with unit suffix
* @param {number|string} [height] Height as a number of pixels or CSS string with unit suffix
*/
-OO.ui.ClippableElement.prototype.setIdealSize = function ( width, height ) {
+OO.ui.mixin.ClippableElement.prototype.setIdealSize = function ( width, height ) {
this.idealWidth = width;
this.idealHeight = height;
@@ -6374,47 +6777,56 @@ OO.ui.ClippableElement.prototype.setIdealSize = function ( width, height ) {
*
* @chainable
*/
-OO.ui.ClippableElement.prototype.clip = function () {
+OO.ui.mixin.ClippableElement.prototype.clip = function () {
+ var $container, extraHeight, extraWidth, ccOffset,
+ $scrollableContainer, scOffset, scHeight, scWidth,
+ ccWidth, scrollerIsWindow, scrollTop, scrollLeft,
+ desiredWidth, desiredHeight, allotedWidth, allotedHeight,
+ naturalWidth, naturalHeight, clipWidth, clipHeight,
+ buffer = 7; // Chosen by fair dice roll
+
if ( !this.clipping ) {
- // this.$clippableContainer and this.$clippableWindow are null, so the below will fail
+ // this.$clippableScrollableContainer and this.$clippableWindow are null, so the below will fail
return this;
}
- var buffer = 7, // Chosen by fair dice roll
- cOffset = this.$clippable.offset(),
- $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 = 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;
+ $container = this.$clippableContainer || this.$clippable;
+ extraHeight = $container.outerHeight() - this.$clippable.outerHeight();
+ extraWidth = $container.outerWidth() - this.$clippable.outerWidth();
+ ccOffset = $container.offset();
+ $scrollableContainer = this.$clippableScrollableContainer.is( 'html, body' ) ?
+ this.$clippableWindow : this.$clippableScrollableContainer;
+ scOffset = $scrollableContainer.offset() || { top: 0, left: 0 };
+ scHeight = $scrollableContainer.innerHeight() - buffer;
+ scWidth = $scrollableContainer.innerWidth() - buffer;
+ ccWidth = $container.outerWidth() + buffer;
+ scrollerIsWindow = this.$clippableScroller[ 0 ] === this.$clippableWindow[ 0 ];
+ scrollTop = scrollerIsWindow ? this.$clippableScroller.scrollTop() : 0;
+ scrollLeft = scrollerIsWindow ? this.$clippableScroller.scrollLeft() : 0;
+ desiredWidth = ccOffset.left < 0 ?
+ ccWidth + ccOffset.left :
+ ( scOffset.left + scrollLeft + scWidth ) - ccOffset.left;
+ desiredHeight = ( scOffset.top + scrollTop + scHeight ) - ccOffset.top;
+ allotedWidth = desiredWidth - extraWidth;
+ allotedHeight = desiredHeight - extraHeight;
+ naturalWidth = this.$clippable.prop( 'scrollWidth' );
+ naturalHeight = this.$clippable.prop( 'scrollHeight' );
+ clipWidth = allotedWidth < naturalWidth;
+ clipHeight = allotedHeight < naturalHeight;
if ( clipWidth ) {
- this.$clippable.css( { overflowX: 'scroll', width: desiredWidth } );
+ this.$clippable.css( { overflowX: 'scroll', width: Math.max( 0, allotedWidth ) } );
} else {
- this.$clippable.css( { width: this.idealWidth || '', overflowX: '' } );
+ this.$clippable.css( { width: this.idealWidth ? this.idealWidth - extraWidth : '', overflowX: '' } );
}
if ( clipHeight ) {
- this.$clippable.css( { overflowY: 'scroll', height: desiredHeight } );
+ this.$clippable.css( { overflowY: 'scroll', height: Math.max( 0, allotedHeight ) } );
} else {
- this.$clippable.css( { height: this.idealHeight || '', overflowY: '' } );
+ this.$clippable.css( { height: this.idealHeight ? this.idealHeight - extraHeight : '', overflowY: '' } );
}
// If we stopped clipping in at least one of the dimensions
- if ( !clipWidth || !clipHeight ) {
+ if ( ( this.clippedHorizontally && !clipWidth ) || ( this.clippedVertically && !clipHeight ) ) {
OO.ui.Element.static.reconsiderScrollbars( this.$clippable[ 0 ] );
}
@@ -6425,19 +6837,302 @@ OO.ui.ClippableElement.prototype.clip = function () {
};
/**
- * Generic toolbar tool.
+ * Element that will stick under a specified container, even when it is inserted elsewhere in the
+ * document (for example, in a OO.ui.Window's $overlay).
+ *
+ * The elements's position is automatically calculated and maintained when window is resized or the
+ * page is scrolled. If you reposition the container manually, you have to call #position to make
+ * sure the element is still placed correctly.
+ *
+ * As positioning is only possible when both the element and the container are attached to the DOM
+ * and visible, it's only done after you call #togglePositioning. You might want to do this inside
+ * the #toggle method to display a floating popup, for example.
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$floatable] Node to position, assigned to #$floatable, omit to use #$element
+ * @cfg {jQuery} [$floatableContainer] Node to position below
+ */
+OO.ui.mixin.FloatableElement = function OoUiMixinFloatableElement( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Properties
+ this.$floatable = null;
+ this.$floatableContainer = null;
+ this.$floatableWindow = null;
+ this.$floatableClosestScrollable = null;
+ this.onFloatableScrollHandler = this.position.bind( this );
+ this.onFloatableWindowResizeHandler = this.position.bind( this );
+
+ // Initialization
+ this.setFloatableContainer( config.$floatableContainer );
+ this.setFloatableElement( config.$floatable || this.$element );
+};
+
+/* Methods */
+
+/**
+ * Set floatable element.
+ *
+ * If an element is already set, it will be cleaned up before setting up the new element.
+ *
+ * @param {jQuery} $floatable Element to make floatable
+ */
+OO.ui.mixin.FloatableElement.prototype.setFloatableElement = function ( $floatable ) {
+ if ( this.$floatable ) {
+ this.$floatable.removeClass( 'oo-ui-floatableElement-floatable' );
+ this.$floatable.css( { left: '', top: '' } );
+ }
+
+ this.$floatable = $floatable.addClass( 'oo-ui-floatableElement-floatable' );
+ this.position();
+};
+
+/**
+ * Set floatable container.
+ *
+ * The element will be always positioned under the specified container.
+ *
+ * @param {jQuery|null} $floatableContainer Container to keep visible, or null to unset
+ */
+OO.ui.mixin.FloatableElement.prototype.setFloatableContainer = function ( $floatableContainer ) {
+ this.$floatableContainer = $floatableContainer;
+ if ( this.$floatable ) {
+ this.position();
+ }
+};
+
+/**
+ * Toggle positioning.
+ *
+ * Do not turn positioning on until after the element is attached to the DOM and visible.
+ *
+ * @param {boolean} [positioning] Enable positioning, omit to toggle
+ * @chainable
+ */
+OO.ui.mixin.FloatableElement.prototype.togglePositioning = function ( positioning ) {
+ var closestScrollableOfContainer, closestScrollableOfFloatable;
+
+ positioning = positioning === undefined ? !this.positioning : !!positioning;
+
+ if ( this.positioning !== positioning ) {
+ this.positioning = positioning;
+
+ closestScrollableOfContainer = OO.ui.Element.static.getClosestScrollableContainer( this.$floatableContainer[ 0 ] );
+ closestScrollableOfFloatable = OO.ui.Element.static.getClosestScrollableContainer( this.$floatable[ 0 ] );
+ if ( closestScrollableOfContainer !== closestScrollableOfFloatable ) {
+ // If the scrollable is the root, we have to listen to scroll events
+ // on the window because of browser inconsistencies (or do we? someone should verify this)
+ if ( $( closestScrollableOfContainer ).is( 'html, body' ) ) {
+ closestScrollableOfContainer = OO.ui.Element.static.getWindow( closestScrollableOfContainer );
+ }
+ }
+
+ if ( positioning ) {
+ this.$floatableWindow = $( this.getElementWindow() );
+ this.$floatableWindow.on( 'resize', this.onFloatableWindowResizeHandler );
+
+ if ( closestScrollableOfContainer !== closestScrollableOfFloatable ) {
+ this.$floatableClosestScrollable = $( closestScrollableOfContainer );
+ this.$floatableClosestScrollable.on( 'scroll', this.onFloatableScrollHandler );
+ }
+
+ // Initial position after visible
+ this.position();
+ } else {
+ if ( this.$floatableWindow ) {
+ this.$floatableWindow.off( 'resize', this.onFloatableWindowResizeHandler );
+ this.$floatableWindow = null;
+ }
+
+ if ( this.$floatableClosestScrollable ) {
+ this.$floatableClosestScrollable.off( 'scroll', this.onFloatableScrollHandler );
+ this.$floatableClosestScrollable = null;
+ }
+
+ this.$floatable.css( { left: '', top: '' } );
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Position the floatable below its container.
+ *
+ * This should only be done when both of them are attached to the DOM and visible.
+ *
+ * @chainable
+ */
+OO.ui.mixin.FloatableElement.prototype.position = function () {
+ var pos;
+
+ if ( !this.positioning ) {
+ return this;
+ }
+
+ pos = OO.ui.Element.static.getRelativePosition( this.$floatableContainer, this.$floatable.offsetParent() );
+
+ // Position under container
+ pos.top += this.$floatableContainer.height();
+ this.$floatable.css( pos );
+
+ // We updated the position, so re-evaluate the clipping state.
+ // (ClippableElement does not listen to 'scroll' events on $floatableContainer's parent, and so
+ // will not notice the need to update itself.)
+ // TODO: This is terrible, we shouldn't need to know about ClippableElement at all here. Why does
+ // it not listen to the right events in the right places?
+ if ( this.clip ) {
+ this.clip();
+ }
+
+ return this;
+};
+
+/**
+ * AccessKeyedElement is mixed into other classes to provide an `accesskey` attribute.
+ * Accesskeys allow an user to go to a specific element by using
+ * a shortcut combination of a browser specific keys + the key
+ * set to the field.
+ *
+ * @example
+ * // AccessKeyedElement provides an 'accesskey' attribute to the
+ * // ButtonWidget class
+ * var button = new OO.ui.ButtonWidget( {
+ * label: 'Button with Accesskey',
+ * accessKey: 'k'
+ * } );
+ * $( 'body' ).append( button.$element );
+ *
+ * @abstract
+ * @class
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {jQuery} [$accessKeyed] The element to which the `accesskey` attribute is applied.
+ * If this config is omitted, the accesskey functionality is applied to $element, the
+ * element created by the class.
+ * @cfg {string|Function} [accessKey] The key or a function that returns the key. If
+ * this config is omitted, no accesskey will be added.
+ */
+OO.ui.mixin.AccessKeyedElement = function OoUiMixinAccessKeyedElement( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Properties
+ this.$accessKeyed = null;
+ this.accessKey = null;
+
+ // Initialization
+ this.setAccessKey( config.accessKey || null );
+ this.setAccessKeyedElement( config.$accessKeyed || this.$element );
+};
+
+/* Setup */
+
+OO.initClass( OO.ui.mixin.AccessKeyedElement );
+
+/* Static Properties */
+
+/**
+ * The access key, a function that returns a key, or `null` for no accesskey.
+ *
+ * @static
+ * @inheritable
+ * @property {string|Function|null}
+ */
+OO.ui.mixin.AccessKeyedElement.static.accessKey = null;
+
+/* Methods */
+
+/**
+ * Set the accesskeyed element.
+ *
+ * This method is used to retarget a AccessKeyedElement 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} $accessKeyed Element that should use the 'accesskeyes' functionality
+ */
+OO.ui.mixin.AccessKeyedElement.prototype.setAccessKeyedElement = function ( $accessKeyed ) {
+ if ( this.$accessKeyed ) {
+ this.$accessKeyed.removeAttr( 'accesskey' );
+ }
+
+ this.$accessKeyed = $accessKeyed;
+ if ( this.accessKey ) {
+ this.$accessKeyed.attr( 'accesskey', this.accessKey );
+ }
+};
+
+/**
+ * Set accesskey.
+ *
+ * @param {string|Function|null} accesskey Key, a function that returns a key, or `null` for no accesskey
+ * @chainable
+ */
+OO.ui.mixin.AccessKeyedElement.prototype.setAccessKey = function ( accessKey ) {
+ accessKey = typeof accessKey === 'string' ? OO.ui.resolveMsg( accessKey ) : null;
+
+ if ( this.accessKey !== accessKey ) {
+ if ( this.$accessKeyed ) {
+ if ( accessKey !== null ) {
+ this.$accessKeyed.attr( 'accesskey', accessKey );
+ } else {
+ this.$accessKeyed.removeAttr( 'accesskey' );
+ }
+ }
+ this.accessKey = accessKey;
+ }
+
+ return this;
+};
+
+/**
+ * Get accesskey.
+ *
+ * @return {string} accessKey string
+ */
+OO.ui.mixin.AccessKeyedElement.prototype.getAccessKey = function () {
+ return this.accessKey;
+};
+
+/**
+ * Tools, together with {@link OO.ui.ToolGroup toolgroups}, constitute {@link OO.ui.Toolbar toolbars}.
+ * Each tool is configured with a static name, title, and icon and is customized with the command to carry
+ * out when the tool is selected. Tools must also be registered with a {@link OO.ui.ToolFactory tool factory},
+ * which creates the tools on demand.
+ *
+ * Tools are added to toolgroups ({@link OO.ui.ListToolGroup ListToolGroup},
+ * {@link OO.ui.BarToolGroup BarToolGroup}, or {@link OO.ui.MenuToolGroup MenuToolGroup}), which determine how
+ * the tool is displayed in the toolbar. See {@link OO.ui.Toolbar toolbars} for an example.
+ *
+ * For more information, please see the [OOjs UI documentation on MediaWiki][1].
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Toolbars
*
* @abstract
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.FlaggedElement
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.FlaggedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
* @param {OO.ui.ToolGroup} toolGroup
* @param {Object} [config] Configuration options
- * @cfg {string|Function} [title] Title text or a function that returns text
+ * @cfg {string|Function} [title] 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.
+ *
+ * The title is used in different ways depending on the type of toolgroup that contains the tool. The
+ * title is used as a tooltip if the tool is part of a {@link OO.ui.BarToolGroup bar} toolgroup, or as the label text if the tool is
+ * part of a {@link OO.ui.ListToolGroup list} or {@link OO.ui.MenuToolGroup menu} toolgroup.
+ *
+ * For bar toolgroups, a description of the accelerator key is appended to the title if an accelerator key
+ * is associated with an action by the same name as the tool and accelerator functionality has been added to the application.
+ * To add accelerator key functionality, you must subclass OO.ui.Toolbar and override the {@link OO.ui.Toolbar#getToolAccelerator getToolAccelerator} method.
*/
OO.ui.Tool = function OoUiTool( toolGroup, config ) {
// Allow passing positional parameters inside the config object
@@ -6450,7 +7145,7 @@ OO.ui.Tool = function OoUiTool( toolGroup, config ) {
config = config || {};
// Parent constructor
- OO.ui.Tool.super.call( this, config );
+ OO.ui.Tool.parent.call( this, config );
// Properties
this.toolGroup = toolGroup;
@@ -6462,9 +7157,9 @@ OO.ui.Tool = function OoUiTool( toolGroup, config ) {
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 } ) );
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.FlaggedElement.call( this, config );
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$link } ) );
// Events
this.toolbar.connect( this, { updateState: 'onUpdateState' } );
@@ -6497,15 +7192,9 @@ OO.ui.Tool = function OoUiTool( toolGroup, config ) {
/* Setup */
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 */
-
-/**
- * @event select
- */
+OO.mixinClass( OO.ui.Tool, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.Tool, OO.ui.mixin.FlaggedElement );
+OO.mixinClass( OO.ui.Tool, OO.ui.mixin.TabIndexedElement );
/* Static Properties */
@@ -6518,6 +7207,9 @@ OO.ui.Tool.static.tagName = 'span';
/**
* Symbolic name of tool.
*
+ * The symbolic name is used internally to register the tool with a {@link OO.ui.ToolFactory ToolFactory}. It can
+ * also be used when adding tools to toolgroups.
+ *
* @abstract
* @static
* @inheritable
@@ -6526,7 +7218,10 @@ OO.ui.Tool.static.tagName = 'span';
OO.ui.Tool.static.name = '';
/**
- * Tool group.
+ * Symbolic name of the group.
+ *
+ * The group name is used to associate tools with each other so that they can be selected later by
+ * a {@link OO.ui.ToolGroup toolgroup}.
*
* @abstract
* @static
@@ -6536,22 +7231,17 @@ OO.ui.Tool.static.name = '';
OO.ui.Tool.static.group = '';
/**
- * Tool title.
- *
- * Title is used as a tooltip when the tool is part of a bar tool group, or a label when the tool
- * is part of a list or menu tool group. If a trigger is associated with an action by the same name
- * as the tool, a description of its keyboard shortcut for the appropriate platform will be
- * appended to the title if the tool is part of a bar tool group.
+ * Tool title text or a function that returns title text. The value of the static property is overridden if the #title config option is used.
*
* @abstract
* @static
* @inheritable
- * @property {string|Function} Title text or a function that returns text
+ * @property {string|Function}
*/
OO.ui.Tool.static.title = '';
/**
- * Whether this tool should be displayed with both title and label when used in a bar tool group.
+ * Display both icon and label when the tool is used in a {@link OO.ui.BarToolGroup bar} toolgroup.
* Normally only the icon is displayed, or only the label if no icon is given.
*
* @static
@@ -6561,7 +7251,10 @@ OO.ui.Tool.static.title = '';
OO.ui.Tool.static.displayBothIconAndLabel = false;
/**
- * Tool can be automatically added to catch-all groups.
+ * Add tool to catch-all groups automatically.
+ *
+ * A catch-all group, which contains all tools that do not currently belong to a toolgroup,
+ * can be included in a toolgroup using the wildcard selector, an asterisk (*).
*
* @static
* @inheritable
@@ -6570,7 +7263,11 @@ OO.ui.Tool.static.displayBothIconAndLabel = false;
OO.ui.Tool.static.autoAddToCatchall = true;
/**
- * Tool can be automatically added to named groups.
+ * Add tool to named groups automatically.
+ *
+ * By default, tools that are configured with a static ‘group’ property are added
+ * to that group and will be selected when the symbolic name of the group is specified (e.g., when
+ * toolgroups include tools by group name).
*
* @static
* @property {boolean}
@@ -6581,6 +7278,10 @@ OO.ui.Tool.static.autoAddToGroup = true;
/**
* Check if this tool is compatible with given data.
*
+ * This is a stub that can be overriden to provide support for filtering tools based on an
+ * arbitrary piece of information (e.g., where the cursor is in a document). The implementation
+ * must also call this method so that the compatibility check can be performed.
+ *
* @static
* @inheritable
* @param {Mixed} data Data to check
@@ -6597,6 +7298,7 @@ OO.ui.Tool.static.isCompatibleWith = function () {
*
* This is an abstract method that must be overridden in a concrete subclass.
*
+ * @protected
* @abstract
*/
OO.ui.Tool.prototype.onUpdateState = function () {
@@ -6610,6 +7312,7 @@ OO.ui.Tool.prototype.onUpdateState = function () {
*
* This is an abstract method that must be overridden in a concrete subclass.
*
+ * @protected
* @abstract
*/
OO.ui.Tool.prototype.onSelect = function () {
@@ -6619,18 +7322,24 @@ OO.ui.Tool.prototype.onSelect = function () {
};
/**
- * Check if the button is active.
+ * Check if the tool is active.
+ *
+ * Tools become active when their #onSelect or #onUpdateState handlers change them to appear pressed
+ * with the #setActive method. Additional CSS is applied to the tool to reflect the active state.
*
- * @return {boolean} Button is active
+ * @return {boolean} Tool is active
*/
OO.ui.Tool.prototype.isActive = function () {
return this.active;
};
/**
- * Make the button appear active or inactive.
+ * Make the tool appear active or inactive.
*
- * @param {boolean} state Make button appear active
+ * This method should be called within #onSelect or #onUpdateState event handlers to make the tool
+ * appear pressed or not.
+ *
+ * @param {boolean} state Make tool appear active
*/
OO.ui.Tool.prototype.setActive = function ( state ) {
this.active = !!state;
@@ -6642,7 +7351,7 @@ OO.ui.Tool.prototype.setActive = function ( state ) {
};
/**
- * Get the tool title.
+ * Set the tool #title.
*
* @param {string|Function} title Title text or a function that returns text
* @chainable
@@ -6654,7 +7363,7 @@ OO.ui.Tool.prototype.setTitle = function ( title ) {
};
/**
- * Get the tool title.
+ * Get the tool #title.
*
* @return {string} Title text
*/
@@ -6698,6 +7407,9 @@ OO.ui.Tool.prototype.updateTitle = function () {
/**
* Destroy tool.
+ *
+ * Destroying the tool removes all event handlers and the tool’s DOM elements.
+ * Call this method whenever you are done using a tool.
*/
OO.ui.Tool.prototype.destroy = function () {
this.toolbar.disconnect( this );
@@ -6705,11 +7417,23 @@ OO.ui.Tool.prototype.destroy = function () {
};
/**
- * Collection of tool groups.
+ * Toolbars are complex interface components that permit users to easily access a variety
+ * of {@link OO.ui.Tool tools} (e.g., formatting commands) and actions, which are additional commands that are
+ * part of the toolbar, but not configured as tools.
*
- * The following is a minimal example using several tools and tool groups.
+ * Individual tools are customized and then registered with a {@link OO.ui.ToolFactory tool factory}, which creates
+ * the tools on demand. Each tool has a symbolic name (used when registering the tool), a title (e.g., ‘Insert
+ * picture’), and an icon.
+ *
+ * Individual tools are organized in {@link OO.ui.ToolGroup toolgroups}, which can be {@link OO.ui.MenuToolGroup menus}
+ * of tools, {@link OO.ui.ListToolGroup lists} of tools, or a single {@link OO.ui.BarToolGroup bar} of tools.
+ * The arrangement and order of the toolgroups is customized when the toolbar is set up. Tools can be presented in
+ * any order, but each can only appear once in the toolbar.
+ *
+ * The following is an example of a basic toolbar.
*
* @example
+ * // Example of a toolbar
* // Create the toolbar
* var toolFactory = new OO.ui.ToolFactory();
* var toolGroupFactory = new OO.ui.ToolGroupFactory();
@@ -6722,7 +7446,7 @@ OO.ui.Tool.prototype.destroy = function () {
*
* // Create a class inheriting from OO.ui.Tool
* function PictureTool() {
- * PictureTool.super.apply( this, arguments );
+ * PictureTool.parent.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
@@ -6741,7 +7465,7 @@ OO.ui.Tool.prototype.destroy = function () {
*
* // Register two more tools, nothing interesting here
* function SettingsTool() {
- * SettingsTool.super.apply( this, arguments );
+ * SettingsTool.parent.apply( this, arguments );
* }
* OO.inheritClass( SettingsTool, OO.ui.Tool );
* SettingsTool.static.name = 'settings';
@@ -6755,7 +7479,7 @@ OO.ui.Tool.prototype.destroy = function () {
*
* // Register two more tools, nothing interesting here
* function StuffTool() {
- * StuffTool.super.apply( this, arguments );
+ * StuffTool.parent.apply( this, arguments );
* }
* OO.inheritClass( StuffTool, OO.ui.Tool );
* StuffTool.static.name = 'stuff';
@@ -6822,7 +7546,7 @@ OO.ui.Tool.prototype.destroy = function () {
* // document.
* toolbar.initialize();
*
- * The following example extends the previous one to illustrate 'menu' tool groups and the usage of
+ * The following example extends the previous one to illustrate 'menu' toolgroups and the usage of
* 'updateState' event.
*
* @example
@@ -6838,7 +7562,7 @@ OO.ui.Tool.prototype.destroy = function () {
*
* // Create a class inheriting from OO.ui.Tool
* function PictureTool() {
- * PictureTool.super.apply( this, arguments );
+ * PictureTool.parent.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
@@ -6862,7 +7586,7 @@ OO.ui.Tool.prototype.destroy = function () {
*
* // Register two more tools, nothing interesting here
* function SettingsTool() {
- * SettingsTool.super.apply( this, arguments );
+ * SettingsTool.parent.apply( this, arguments );
* this.reallyActive = false;
* }
* OO.inheritClass( SettingsTool, OO.ui.Tool );
@@ -6883,7 +7607,7 @@ OO.ui.Tool.prototype.destroy = function () {
*
* // Register two more tools, nothing interesting here
* function StuffTool() {
- * StuffTool.super.apply( this, arguments );
+ * StuffTool.parent.apply( this, arguments );
* this.reallyActive = false;
* }
* OO.inheritClass( StuffTool, OO.ui.Tool );
@@ -6958,14 +7682,16 @@ OO.ui.Tool.prototype.destroy = function () {
* @class
* @extends OO.ui.Element
* @mixins OO.EventEmitter
- * @mixins OO.ui.GroupElement
+ * @mixins OO.ui.mixin.GroupElement
*
* @constructor
* @param {OO.ui.ToolFactory} toolFactory Factory for creating tools
- * @param {OO.ui.ToolGroupFactory} toolGroupFactory Factory for creating tool groups
+ * @param {OO.ui.ToolGroupFactory} toolGroupFactory Factory for creating toolgroups
* @param {Object} [config] Configuration options
- * @cfg {boolean} [actions] Add an actions section opposite to the tools
- * @cfg {boolean} [shadow] Add a shadow below the toolbar
+ * @cfg {boolean} [actions] Add an actions section to the toolbar. Actions are commands that are included
+ * in the toolbar, but are not configured as tools. By default, actions are displayed on the right side of
+ * the toolbar.
+ * @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
@@ -6979,11 +7705,11 @@ OO.ui.Toolbar = function OoUiToolbar( toolFactory, toolGroupFactory, config ) {
config = config || {};
// Parent constructor
- OO.ui.Toolbar.super.call( this, config );
+ OO.ui.Toolbar.parent.call( this, config );
// Mixin constructors
OO.EventEmitter.call( this );
- OO.ui.GroupElement.call( this, config );
+ OO.ui.mixin.GroupElement.call( this, config );
// Properties
this.toolFactory = toolFactory;
@@ -7018,7 +7744,7 @@ OO.ui.Toolbar = function OoUiToolbar( toolFactory, toolGroupFactory, config ) {
OO.inheritClass( OO.ui.Toolbar, OO.ui.Element );
OO.mixinClass( OO.ui.Toolbar, OO.EventEmitter );
-OO.mixinClass( OO.ui.Toolbar, OO.ui.GroupElement );
+OO.mixinClass( OO.ui.Toolbar, OO.ui.mixin.GroupElement );
/* Methods */
@@ -7032,9 +7758,9 @@ OO.ui.Toolbar.prototype.getToolFactory = function () {
};
/**
- * Get the tool group factory.
+ * Get the toolgroup factory.
*
- * @return {OO.Factory} Tool group factory
+ * @return {OO.Factory} Toolgroup factory
*/
OO.ui.Toolbar.prototype.getToolGroupFactory = function () {
return this.toolGroupFactory;
@@ -7043,6 +7769,7 @@ OO.ui.Toolbar.prototype.getToolGroupFactory = function () {
/**
* Handles mouse down events.
*
+ * @private
* @param {jQuery.Event} e Mouse down event
*/
OO.ui.Toolbar.prototype.onPointerDown = function ( e ) {
@@ -7071,26 +7798,27 @@ OO.ui.Toolbar.prototype.onWindowResize = function () {
* 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();
+ if ( !this.initialized ) {
+ this.initialized = true;
+ this.narrowThreshold = this.$group.width() + this.$actions.width();
+ $( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
+ this.onWindowResize();
+ }
};
/**
- * Setup toolbar.
+ * Set up the toolbar.
*
- * Tools can be specified in the following ways:
+ * The toolbar is set up with a list of toolgroup configurations that specify the type of
+ * toolgroup ({@link OO.ui.BarToolGroup bar}, {@link OO.ui.MenuToolGroup menu}, or {@link OO.ui.ListToolGroup list})
+ * to add and which tools to include, exclude, promote, or demote within that toolgroup. Please
+ * see {@link OO.ui.ToolGroup toolgroups} for more information about including tools in toolgroups.
*
- * - A specific tool: `{ name: 'tool-name' }` or `'tool-name'`
- * - All tools in a group: `{ group: 'group-name' }`
- * - All tools: `'*'` - Using this will make the group a list with a "More" label by default
- *
- * @param {Object.<string,Array>} groups List of tool group configurations
- * @param {Array|string} [groups.include] Tools to include
- * @param {Array|string} [groups.exclude] Tools to exclude
- * @param {Array|string} [groups.promote] Tools to promote to the beginning
- * @param {Array|string} [groups.demote] Tools to demote to the end
+ * @param {Object.<string,Array>} groups List of toolgroup configurations
+ * @param {Array|string} [groups.include] Tools to include in the toolgroup
+ * @param {Array|string} [groups.exclude] Tools to exclude from the toolgroup
+ * @param {Array|string} [groups.promote] Tools to promote to the beginning of the toolgroup
+ * @param {Array|string} [groups.demote] Tools to demote to the end of the toolgroup
*/
OO.ui.Toolbar.prototype.setup = function ( groups ) {
var i, len, type, group,
@@ -7122,7 +7850,7 @@ OO.ui.Toolbar.prototype.setup = function ( groups ) {
};
/**
- * Remove all tools and groups from the toolbar.
+ * Remove all tools and toolgroups from the toolbar.
*/
OO.ui.Toolbar.prototype.reset = function () {
var i, len;
@@ -7136,9 +7864,10 @@ OO.ui.Toolbar.prototype.reset = function () {
};
/**
- * Destroys toolbar, removing event handlers and DOM elements.
+ * Destroy the toolbar.
*
- * Call this whenever you are done using a toolbar.
+ * Destroying the toolbar removes all event handlers and DOM elements that constitute the toolbar. Call
+ * this method whenever you are done using a toolbar.
*/
OO.ui.Toolbar.prototype.destroy = function () {
$( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
@@ -7147,7 +7876,9 @@ OO.ui.Toolbar.prototype.destroy = function () {
};
/**
- * Check if tool has not been used yet.
+ * Check if the tool is available.
+ *
+ * Available tools are ones that have not yet been added to the toolbar.
*
* @param {string} name Symbolic name of tool
* @return {boolean} Tool is available
@@ -7177,7 +7908,9 @@ OO.ui.Toolbar.prototype.releaseTool = function ( tool ) {
/**
* Get accelerator label for tool.
*
- * This is a stub that should be overridden to provide access to accelerator information.
+ * The OOjs UI library does not contain an accelerator system, but this is the hook for one. To
+ * use an accelerator system, subclass the toolbar and override this method, which is meant to return a label
+ * that describes the accelerator keys for the tool passed (by symbolic name) to the method.
*
* @param {string} name Symbolic name of tool
* @return {string|undefined} Tool accelerator label if available
@@ -7187,26 +7920,44 @@ OO.ui.Toolbar.prototype.getToolAccelerator = function () {
};
/**
- * Collection of tools.
+ * ToolGroups are collections of {@link OO.ui.Tool tools} that are used in a {@link OO.ui.Toolbar toolbar}.
+ * The type of toolgroup ({@link OO.ui.ListToolGroup list}, {@link OO.ui.BarToolGroup bar}, or {@link OO.ui.MenuToolGroup menu})
+ * to which a tool belongs determines how the tool is arranged and displayed in the toolbar. Toolgroups
+ * themselves are created on demand with a {@link OO.ui.ToolGroupFactory toolgroup factory}.
*
- * Tools can be specified in the following ways:
+ * Toolgroups can contain individual tools, groups of tools, or all available tools:
*
- * - A specific tool: `{ name: 'tool-name' }` or `'tool-name'`
- * - All tools in a group: `{ group: 'group-name' }`
- * - All tools: `'*'`
+ * To include an individual tool (or array of individual tools), specify tools by symbolic name:
+ *
+ * include: [ 'tool-name' ] or [ { name: 'tool-name' }]
+ *
+ * To include a group of tools, specify the group name. (The tool's static ‘group’ config is used to assign the tool to a group.)
+ *
+ * include: [ { group: 'group-name' } ]
+ *
+ * To include all tools that are not yet assigned to a toolgroup, use the catch-all selector, an asterisk (*):
+ *
+ * include: '*'
+ *
+ * See {@link OO.ui.Toolbar toolbars} for a full example. For more information about toolbars in general,
+ * please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Toolbars
*
* @abstract
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.GroupElement
+ * @mixins OO.ui.mixin.GroupElement
*
* @constructor
* @param {OO.ui.Toolbar} toolbar
* @param {Object} [config] Configuration options
- * @cfg {Array|string} [include=[]] List of tools to include
- * @cfg {Array|string} [exclude=[]] List of tools to exclude
- * @cfg {Array|string} [promote=[]] List of tools to promote to the beginning
- * @cfg {Array|string} [demote=[]] List of tools to demote to the end
+ * @cfg {Array|string} [include=[]] List of tools to include in the toolgroup.
+ * @cfg {Array|string} [exclude=[]] List of tools to exclude from the toolgroup.
+ * @cfg {Array|string} [promote=[]] List of tools to promote to the beginning of the toolgroup.
+ * @cfg {Array|string} [demote=[]] List of tools to demote to the end of the toolgroup.
+ * This setting is particularly useful when tools have been added to the toolgroup
+ * en masse (e.g., via the catch-all selector).
*/
OO.ui.ToolGroup = function OoUiToolGroup( toolbar, config ) {
// Allow passing positional parameters inside the config object
@@ -7219,10 +7970,10 @@ OO.ui.ToolGroup = function OoUiToolGroup( toolbar, config ) {
config = config || {};
// Parent constructor
- OO.ui.ToolGroup.super.call( this, config );
+ OO.ui.ToolGroup.parent.call( this, config );
// Mixin constructors
- OO.ui.GroupElement.call( this, config );
+ OO.ui.mixin.GroupElement.call( this, config );
// Properties
this.toolbar = toolbar;
@@ -7261,7 +8012,7 @@ OO.ui.ToolGroup = function OoUiToolGroup( toolbar, config ) {
/* Setup */
OO.inheritClass( OO.ui.ToolGroup, OO.ui.Widget );
-OO.mixinClass( OO.ui.ToolGroup, OO.ui.GroupElement );
+OO.mixinClass( OO.ui.ToolGroup, OO.ui.mixin.GroupElement );
/* Events */
@@ -7283,6 +8034,11 @@ OO.ui.ToolGroup.static.titleTooltips = false;
/**
* Show acceleration labels in tooltips.
*
+ * Note: The OOjs UI library does not include an accelerator system, but does contain
+ * a hook for one. To use an accelerator system, subclass the {@link OO.ui.Toolbar toolbar} and
+ * override the {@link OO.ui.Toolbar#getToolAccelerator getToolAccelerator} method, which is
+ * meant to return a label that describes the accelerator keys for a given tool (e.g., 'Ctrl + M').
+ *
* @static
* @inheritable
* @property {boolean}
@@ -7304,7 +8060,7 @@ OO.ui.ToolGroup.static.autoDisable = true;
* @inheritdoc
*/
OO.ui.ToolGroup.prototype.isDisabled = function () {
- return this.autoDisabled || OO.ui.ToolGroup.super.prototype.isDisabled.apply( this, arguments );
+ return this.autoDisabled || OO.ui.ToolGroup.parent.prototype.isDisabled.apply( this, arguments );
};
/**
@@ -7323,12 +8079,13 @@ OO.ui.ToolGroup.prototype.updateDisabled = function () {
}
this.autoDisabled = allDisabled;
}
- OO.ui.ToolGroup.super.prototype.updateDisabled.apply( this, arguments );
+ OO.ui.ToolGroup.parent.prototype.updateDisabled.apply( this, arguments );
};
/**
* Handle mouse down and key down events.
*
+ * @protected
* @param {jQuery.Event} e Mouse down or key down event
*/
OO.ui.ToolGroup.prototype.onMouseKeyDown = function ( e ) {
@@ -7339,8 +8096,8 @@ OO.ui.ToolGroup.prototype.onMouseKeyDown = function ( e ) {
this.pressed = this.getTargetTool( e );
if ( this.pressed ) {
this.pressed.setActive( true );
- this.getElementDocument().addEventListener( 'mouseup', this.onCapturedMouseKeyUpHandler, true );
- this.getElementDocument().addEventListener( 'keyup', this.onCapturedMouseKeyUpHandler, true );
+ OO.ui.addCaptureEventListener( this.getElementDocument(), 'mouseup', this.onCapturedMouseKeyUpHandler );
+ OO.ui.addCaptureEventListener( this.getElementDocument(), 'keyup', this.onCapturedMouseKeyUpHandler );
}
return false;
}
@@ -7349,11 +8106,12 @@ OO.ui.ToolGroup.prototype.onMouseKeyDown = function ( e ) {
/**
* Handle captured mouse up and key up events.
*
+ * @protected
* @param {Event} e Mouse up or key up event
*/
OO.ui.ToolGroup.prototype.onCapturedMouseKeyUp = function ( e ) {
- this.getElementDocument().removeEventListener( 'mouseup', this.onCapturedMouseKeyUpHandler, true );
- this.getElementDocument().removeEventListener( 'keyup', this.onCapturedMouseKeyUpHandler, true );
+ OO.ui.removeCaptureEventListener( this.getElementDocument(), 'mouseup', this.onCapturedMouseKeyUpHandler );
+ OO.ui.removeCaptureEventListener( this.getElementDocument(), 'keyup', this.onCapturedMouseKeyUpHandler );
// 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.onMouseKeyUp( e );
@@ -7362,6 +8120,7 @@ OO.ui.ToolGroup.prototype.onCapturedMouseKeyUp = function ( e ) {
/**
* Handle mouse up and key up events.
*
+ * @protected
* @param {jQuery.Event} e Mouse up or key up event
*/
OO.ui.ToolGroup.prototype.onMouseKeyUp = function ( e ) {
@@ -7382,6 +8141,7 @@ OO.ui.ToolGroup.prototype.onMouseKeyUp = function ( e ) {
/**
* Handle mouse over and focus events.
*
+ * @protected
* @param {jQuery.Event} e Mouse over or focus event
*/
OO.ui.ToolGroup.prototype.onMouseOverFocus = function ( e ) {
@@ -7395,6 +8155,7 @@ OO.ui.ToolGroup.prototype.onMouseOverFocus = function ( e ) {
/**
* Handle mouse out and blur events.
*
+ * @protected
* @param {jQuery.Event} e Mouse out or blur event
*/
OO.ui.ToolGroup.prototype.onMouseOutBlur = function ( e ) {
@@ -7434,6 +8195,7 @@ OO.ui.ToolGroup.prototype.getTargetTool = function ( e ) {
* - a tool being added that may be included
* - a tool already included being overridden
*
+ * @protected
* @param {string} name Symbolic name of tool
*/
OO.ui.ToolGroup.prototype.onToolFactoryRegister = function () {
@@ -7441,9 +8203,9 @@ OO.ui.ToolGroup.prototype.onToolFactoryRegister = function () {
};
/**
- * Get the toolbar this group is in.
+ * Get the toolbar that contains the toolgroup.
*
- * @return {OO.ui.Toolbar} Toolbar of group
+ * @return {OO.ui.Toolbar} Toolbar that contains the toolgroup
*/
OO.ui.ToolGroup.prototype.getToolbar = function () {
return this.toolbar;
@@ -7510,7 +8272,7 @@ OO.ui.ToolGroup.prototype.populate = function () {
};
/**
- * Destroy tool group.
+ * Destroy toolgroup.
*/
OO.ui.ToolGroup.prototype.destroy = function () {
var name;
@@ -7568,7 +8330,7 @@ OO.ui.ToolGroup.prototype.destroy = function () {
*/
OO.ui.MessageDialog = function OoUiMessageDialog( config ) {
// Parent constructor
- OO.ui.MessageDialog.super.call( this, config );
+ OO.ui.MessageDialog.parent.call( this, config );
// Properties
this.verticalActionLayout = null;
@@ -7577,7 +8339,7 @@ OO.ui.MessageDialog = function OoUiMessageDialog( config ) {
this.$element.addClass( 'oo-ui-messageDialog' );
};
-/* Inheritance */
+/* Setup */
OO.inheritClass( OO.ui.MessageDialog, OO.ui.Dialog );
@@ -7624,7 +8386,7 @@ OO.ui.MessageDialog.static.actions = [
* @inheritdoc
*/
OO.ui.MessageDialog.prototype.setManager = function ( manager ) {
- OO.ui.MessageDialog.super.prototype.setManager.call( this, manager );
+ OO.ui.MessageDialog.parent.prototype.setManager.call( this, manager );
// Events
this.manager.connect( this, {
@@ -7639,7 +8401,7 @@ OO.ui.MessageDialog.prototype.setManager = function ( manager ) {
*/
OO.ui.MessageDialog.prototype.onActionResize = function ( action ) {
this.fitActions();
- return OO.ui.MessageDialog.super.prototype.onActionResize.call( this, action );
+ return OO.ui.MessageDialog.parent.prototype.onActionResize.call( this, action );
};
/**
@@ -7659,7 +8421,6 @@ OO.ui.MessageDialog.prototype.onResize = function () {
/**
* Toggle action layout between vertical and horizontal.
*
- *
* @private
* @param {boolean} [value] Layout actions vertically, omit to toggle
* @chainable
@@ -7686,7 +8447,7 @@ OO.ui.MessageDialog.prototype.getActionProcess = function ( action ) {
this.close( { action: action } );
}, this );
}
- return OO.ui.MessageDialog.super.prototype.getActionProcess.call( this, action );
+ return OO.ui.MessageDialog.parent.prototype.getActionProcess.call( this, action );
};
/**
@@ -7703,7 +8464,7 @@ OO.ui.MessageDialog.prototype.getSetupProcess = function ( data ) {
data = data || {};
// Parent method
- return OO.ui.MessageDialog.super.prototype.getSetupProcess.call( this, data )
+ return OO.ui.MessageDialog.parent.prototype.getSetupProcess.call( this, data )
.next( function () {
this.title.setLabel(
data.title !== undefined ? data.title : this.constructor.static.title
@@ -7721,6 +8482,26 @@ OO.ui.MessageDialog.prototype.getSetupProcess = function ( data ) {
/**
* @inheritdoc
*/
+OO.ui.MessageDialog.prototype.getReadyProcess = function ( data ) {
+ data = data || {};
+
+ // Parent method
+ return OO.ui.MessageDialog.parent.prototype.getReadyProcess.call( this, data )
+ .next( function () {
+ // Focus the primary action button
+ var actions = this.actions.get();
+ actions = actions.filter( function ( action ) {
+ return action.getFlags().indexOf( 'primary' ) > -1;
+ } );
+ if ( actions.length > 0 ) {
+ actions[ 0 ].$button.focus();
+ }
+ }, this );
+};
+
+/**
+ * @inheritdoc
+ */
OO.ui.MessageDialog.prototype.getBodyHeight = function () {
var bodyHeight, oldOverflow,
$scrollable = this.container.$element;
@@ -7741,7 +8522,7 @@ OO.ui.MessageDialog.prototype.getBodyHeight = function () {
*/
OO.ui.MessageDialog.prototype.setDimensions = function ( dim ) {
var $scrollable = this.container.$element;
- OO.ui.MessageDialog.super.prototype.setDimensions.call( this, dim );
+ OO.ui.MessageDialog.parent.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.
@@ -7762,7 +8543,7 @@ OO.ui.MessageDialog.prototype.setDimensions = function ( dim ) {
*/
OO.ui.MessageDialog.prototype.initialize = function () {
// Parent method
- OO.ui.MessageDialog.super.prototype.initialize.call( this );
+ OO.ui.MessageDialog.parent.prototype.initialize.call( this );
// Properties
this.$actions = $( '<div>' );
@@ -7793,10 +8574,11 @@ OO.ui.MessageDialog.prototype.attachActions = function () {
var i, len, other, special, others;
// Parent method
- OO.ui.MessageDialog.super.prototype.attachActions.call( this );
+ OO.ui.MessageDialog.parent.prototype.attachActions.call( this );
special = this.actions.getSpecial();
others = this.actions.getOthers();
+
if ( special.safe ) {
this.$actions.append( special.safe.$element );
special.safe.toggleFramed( false );
@@ -7869,7 +8651,7 @@ OO.ui.MessageDialog.prototype.fitActions = function () {
* @example
* // Example: Creating and opening a process dialog window.
* function MyProcessDialog( config ) {
- * MyProcessDialog.super.call( this, config );
+ * MyProcessDialog.parent.call( this, config );
* }
* OO.inheritClass( MyProcessDialog, OO.ui.ProcessDialog );
*
@@ -7880,7 +8662,7 @@ OO.ui.MessageDialog.prototype.fitActions = function () {
* ];
*
* MyProcessDialog.prototype.initialize = function () {
- * MyProcessDialog.super.prototype.initialize.apply( this, arguments );
+ * MyProcessDialog.parent.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 );
@@ -7892,7 +8674,7 @@ OO.ui.MessageDialog.prototype.fitActions = function () {
* dialog.close( { action: action } );
* } );
* }
- * return MyProcessDialog.super.prototype.getActionProcess.call( this, action );
+ * return MyProcessDialog.parent.prototype.getActionProcess.call( this, action );
* };
*
* var windowManager = new OO.ui.WindowManager();
@@ -7913,7 +8695,10 @@ OO.ui.MessageDialog.prototype.fitActions = function () {
*/
OO.ui.ProcessDialog = function OoUiProcessDialog( config ) {
// Parent constructor
- OO.ui.ProcessDialog.super.call( this, config );
+ OO.ui.ProcessDialog.parent.call( this, config );
+
+ // Properties
+ this.fitOnOpen = false;
// Initialization
this.$element.addClass( 'oo-ui-processDialog' );
@@ -7955,7 +8740,7 @@ OO.ui.ProcessDialog.prototype.onActionResize = function ( action ) {
if ( this.actions.isSpecial( action ) ) {
this.fitLabel();
}
- return OO.ui.ProcessDialog.super.prototype.onActionResize.call( this, action );
+ return OO.ui.ProcessDialog.parent.prototype.onActionResize.call( this, action );
};
/**
@@ -7963,7 +8748,7 @@ OO.ui.ProcessDialog.prototype.onActionResize = function ( action ) {
*/
OO.ui.ProcessDialog.prototype.initialize = function () {
// Parent method
- OO.ui.ProcessDialog.super.prototype.initialize.call( this );
+ OO.ui.ProcessDialog.parent.prototype.initialize.call( this );
// Properties
this.$navigation = $( '<div>' );
@@ -8026,7 +8811,7 @@ OO.ui.ProcessDialog.prototype.attachActions = function () {
var i, len, other, special, others;
// Parent method
- OO.ui.ProcessDialog.super.prototype.attachActions.call( this );
+ OO.ui.ProcessDialog.parent.prototype.attachActions.call( this );
special = this.actions.getSpecial();
others = this.actions.getOthers();
@@ -8050,24 +8835,70 @@ OO.ui.ProcessDialog.prototype.attachActions = function () {
*/
OO.ui.ProcessDialog.prototype.executeAction = function ( action ) {
var process = this;
- return OO.ui.ProcessDialog.super.prototype.executeAction.call( this, action )
+ return OO.ui.ProcessDialog.parent.prototype.executeAction.call( this, action )
.fail( function ( errors ) {
process.showErrors( errors || [] );
} );
};
/**
+ * @inheritdoc
+ */
+OO.ui.ProcessDialog.prototype.setDimensions = function () {
+ // Parent method
+ OO.ui.ProcessDialog.parent.prototype.setDimensions.apply( this, arguments );
+
+ this.fitLabel();
+};
+
+/**
* Fit label between actions.
*
* @private
* @chainable
*/
OO.ui.ProcessDialog.prototype.fitLabel = function () {
- var width = Math.max(
- this.$safeActions.is( ':visible' ) ? this.$safeActions.width() : 0,
- this.$primaryActions.is( ':visible' ) ? this.$primaryActions.width() : 0
- );
- this.$location.css( { paddingLeft: width, paddingRight: width } );
+ var safeWidth, primaryWidth, biggerWidth, labelWidth, navigationWidth, leftWidth, rightWidth,
+ size = this.getSizeProperties();
+
+ if ( typeof size.width !== 'number' ) {
+ if ( this.isOpened() ) {
+ navigationWidth = this.$head.width() - 20;
+ } else if ( this.isOpening() ) {
+ if ( !this.fitOnOpen ) {
+ // Size is relative and the dialog isn't open yet, so wait.
+ this.manager.opening.done( this.fitLabel.bind( this ) );
+ this.fitOnOpen = true;
+ }
+ return;
+ } else {
+ return;
+ }
+ } else {
+ navigationWidth = size.width - 20;
+ }
+
+ safeWidth = this.$safeActions.is( ':visible' ) ? this.$safeActions.width() : 0;
+ primaryWidth = this.$primaryActions.is( ':visible' ) ? this.$primaryActions.width() : 0;
+ biggerWidth = Math.max( safeWidth, primaryWidth );
+
+ labelWidth = this.title.$element.width();
+
+ if ( 2 * biggerWidth + labelWidth < navigationWidth ) {
+ // We have enough space to center the label
+ leftWidth = rightWidth = biggerWidth;
+ } else {
+ // Let's hope we at least have enough space not to overlap, because we can't wrap the label…
+ if ( this.getDir() === 'ltr' ) {
+ leftWidth = safeWidth;
+ rightWidth = primaryWidth;
+ } else {
+ leftWidth = primaryWidth;
+ rightWidth = safeWidth;
+ }
+ }
+
+ this.$location.css( { paddingLeft: leftWidth, paddingRight: rightWidth } );
return this;
};
@@ -8103,14 +8934,14 @@ OO.ui.ProcessDialog.prototype.showErrors = function ( errors ) {
}
this.$errorItems = $( items );
if ( recoverable ) {
- abilities[this.currentAction] = true;
+ 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() );
+ this.retryButton.clearFlags().setFlags( actions[ 0 ].getFlags() );
}
} else {
- abilities[this.currentAction] = false;
+ abilities[ this.currentAction ] = false;
this.actions.setAbilities( abilities );
}
if ( warning ) {
@@ -8141,10 +8972,11 @@ OO.ui.ProcessDialog.prototype.hideErrors = function () {
*/
OO.ui.ProcessDialog.prototype.getTeardownProcess = function ( data ) {
// Parent method
- return OO.ui.ProcessDialog.super.prototype.getTeardownProcess.call( this, data )
+ return OO.ui.ProcessDialog.parent.prototype.getTeardownProcess.call( this, data )
.first( function () {
// Make sure to hide errors
this.hideErrors();
+ this.fitOnOpen = false;
}, this );
};
@@ -8170,36 +9002,55 @@ OO.ui.ProcessDialog.prototype.getTeardownProcess = function ( data ) {
* [1]: https://www.mediawiki.org/wiki/OOjs_UI/Layouts/Fields_and_Fieldsets
* @class
* @extends OO.ui.Layout
- * @mixins OO.ui.LabelElement
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.TitledElement
*
* @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.
+ * @cfg {Array} [errors] Error messages about the widget, which will be displayed below the widget.
+ * The array may contain strings or OO.ui.HtmlSnippet instances.
+ * @cfg {Array} [notices] Notices about the widget, which will be displayed below the widget.
+ * The array may contain strings or OO.ui.HtmlSnippet instances.
+ * @cfg {string|OO.ui.HtmlSnippet} [help] Help text. When help text is specified, a "help" icon will appear
+ * in the upper-right corner of the rendered field; clicking it will display the text in a popup.
+ * For important messages, you are advised to use `notices`, as they are always shown.
+ *
+ * @throws {Error} An error is thrown if no widget is specified
*/
OO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {
+ var hasInputWidget, div, i;
+
// 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;
+ // Make sure we have required constructor arguments
+ if ( fieldWidget === undefined ) {
+ throw new Error( 'Widget not found' );
+ }
+
+ hasInputWidget = fieldWidget.constructor.static.supportsSimpleLabel;
// Configuration initialization
config = $.extend( { align: 'left' }, config );
// Parent constructor
- OO.ui.FieldLayout.super.call( this, config );
+ OO.ui.FieldLayout.parent.call( this, config );
// Mixin constructors
- OO.ui.LabelElement.call( this, config );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.TitledElement.call( this, $.extend( {}, config, { $titled: this.$label } ) );
// Properties
this.fieldWidget = fieldWidget;
+ this.errors = config.errors || [];
+ this.notices = config.notices || [];
this.$field = $( '<div>' );
+ this.$messages = $( '<ul>' );
this.$body = $( '<' + ( hasInputWidget ? 'label' : 'div' ) + '>' );
this.align = null;
if ( config.help ) {
@@ -8209,10 +9060,14 @@ OO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {
icon: 'info'
} );
+ div = $( '<div>' );
+ if ( config.help instanceof OO.ui.HtmlSnippet ) {
+ div.html( config.help.toString() );
+ } else {
+ div.text( config.help );
+ }
this.popupButtonWidget.getPopup().$body.append(
- $( '<div>' )
- .text( config.help )
- .addClass( 'oo-ui-fieldLayout-help-content' )
+ div.addClass( 'oo-ui-fieldLayout-help-content' )
);
this.$help = this.popupButtonWidget.$element;
} else {
@@ -8229,19 +9084,31 @@ OO.ui.FieldLayout = function OoUiFieldLayout( fieldWidget, config ) {
this.$element
.addClass( 'oo-ui-fieldLayout' )
.append( this.$help, this.$body );
+ if ( this.errors.length || this.notices.length ) {
+ this.$element.append( this.$messages );
+ }
this.$body.addClass( 'oo-ui-fieldLayout-body' );
+ this.$messages.addClass( 'oo-ui-fieldLayout-messages' );
this.$field
.addClass( 'oo-ui-fieldLayout-field' )
.toggleClass( 'oo-ui-fieldLayout-disable', this.fieldWidget.isDisabled() )
.append( this.fieldWidget.$element );
+ for ( i = 0; i < this.notices.length; i++ ) {
+ this.$messages.append( this.makeMessage( 'notice', this.notices[ i ] ) );
+ }
+ for ( i = 0; i < this.errors.length; i++ ) {
+ this.$messages.append( this.makeMessage( 'error', this.errors[ i ] ) );
+ }
+
this.setAlignment( config.align );
};
/* Setup */
OO.inheritClass( OO.ui.FieldLayout, OO.ui.Layout );
-OO.mixinClass( OO.ui.FieldLayout, OO.ui.LabelElement );
+OO.mixinClass( OO.ui.FieldLayout, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.FieldLayout, OO.ui.mixin.TitledElement );
/* Methods */
@@ -8276,6 +9143,28 @@ OO.ui.FieldLayout.prototype.getField = function () {
};
/**
+ * @param {string} kind 'error' or 'notice'
+ * @param {string|OO.ui.HtmlSnippet} text
+ * @return {jQuery}
+ */
+OO.ui.FieldLayout.prototype.makeMessage = function ( kind, text ) {
+ var $listItem, $icon, message;
+ $listItem = $( '<li>' );
+ if ( kind === 'error' ) {
+ $icon = new OO.ui.IconWidget( { icon: 'alert', flags: [ 'warning' ] } ).$element;
+ } else if ( kind === 'notice' ) {
+ $icon = new OO.ui.IconWidget( { icon: 'info' } ).$element;
+ } else {
+ $icon = '';
+ }
+ message = new OO.ui.LabelWidget( { label: text } );
+ $listItem
+ .append( $icon, message.$element )
+ .addClass( 'oo-ui-fieldLayout-messages-' + kind );
+ return $listItem;
+};
+
+/**
* Set the field alignment mode.
*
* @private
@@ -8347,17 +9236,12 @@ OO.ui.FieldLayout.prototype.setAlignment = function ( value ) {
*
* $( '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
@@ -8367,23 +9251,24 @@ OO.ui.ActionFieldLayout = function OoUiActionFieldLayout( fieldWidget, buttonWid
buttonWidget = config.buttonWidget;
}
- // Configuration initialization
- config = $.extend( { align: 'left' }, config );
-
// Parent constructor
- OO.ui.ActionFieldLayout.super.call( this, fieldWidget, config );
+ OO.ui.ActionFieldLayout.parent.call( this, fieldWidget, config );
// Properties
- this.fieldWidget = fieldWidget;
this.buttonWidget = buttonWidget;
- this.$button = $( '<div>' )
+ this.$button = $( '<div>' );
+ this.$input = $( '<div>' );
+
+ // Initialization
+ this.$element
+ .addClass( 'oo-ui-actionFieldLayout' );
+ this.$button
.addClass( 'oo-ui-actionFieldLayout-button' )
.append( this.buttonWidget.$element );
- this.$input = $( '<div>' )
+ this.$input
.addClass( 'oo-ui-actionFieldLayout-input' )
.append( this.fieldWidget.$element );
this.$field
- .addClass( 'oo-ui-actionFieldLayout' )
.append( this.$input, this.$button );
};
@@ -8425,9 +9310,9 @@ OO.inheritClass( OO.ui.ActionFieldLayout, OO.ui.FieldLayout );
*
* @class
* @extends OO.ui.Layout
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.GroupElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.GroupElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -8438,12 +9323,12 @@ OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
config = config || {};
// Parent constructor
- OO.ui.FieldsetLayout.super.call( this, config );
+ OO.ui.FieldsetLayout.parent.call( this, config );
// Mixin constructors
- OO.ui.IconElement.call( this, config );
- OO.ui.LabelElement.call( this, config );
- OO.ui.GroupElement.call( this, config );
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.GroupElement.call( this, config );
if ( config.help ) {
this.popupButtonWidget = new OO.ui.PopupButtonWidget( {
@@ -8474,9 +9359,9 @@ OO.ui.FieldsetLayout = function OoUiFieldsetLayout( config ) {
/* 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 );
+OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.mixin.GroupElement );
/**
* FormLayouts are used to wrap {@link OO.ui.FieldsetLayout FieldsetLayouts} when you intend to use browser-based
@@ -8531,7 +9416,7 @@ OO.mixinClass( OO.ui.FieldsetLayout, OO.ui.GroupElement );
*
* @class
* @extends OO.ui.Layout
- * @mixins OO.ui.GroupElement
+ * @mixins OO.ui.mixin.GroupElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -8545,14 +9430,19 @@ OO.ui.FormLayout = function OoUiFormLayout( config ) {
config = config || {};
// Parent constructor
- OO.ui.FormLayout.super.call( this, config );
+ OO.ui.FormLayout.parent.call( this, config );
// Mixin constructors
- OO.ui.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
+ OO.ui.mixin.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
// Events
this.$element.on( 'submit', this.onFormSubmit.bind( this ) );
+ // Make sure the action is safe
+ if ( config.action !== undefined && !OO.ui.isSafeUrl( config.action ) ) {
+ throw new Error( 'Potentially unsafe action provided: ' + config.action );
+ }
+
// Initialization
this.$element
.addClass( 'oo-ui-formLayout' )
@@ -8569,7 +9459,7 @@ OO.ui.FormLayout = function OoUiFormLayout( config ) {
/* Setup */
OO.inheritClass( OO.ui.FormLayout, OO.ui.Layout );
-OO.mixinClass( OO.ui.FormLayout, OO.ui.GroupElement );
+OO.mixinClass( OO.ui.FormLayout, OO.ui.mixin.GroupElement );
/* Events */
@@ -8671,7 +9561,7 @@ OO.ui.MenuLayout = function OoUiMenuLayout( config ) {
}, config );
// Parent constructor
- OO.ui.MenuLayout.super.call( this, config );
+ OO.ui.MenuLayout.parent.call( this, config );
/**
* Menu DOM node
@@ -8768,7 +9658,7 @@ OO.ui.MenuLayout.prototype.getMenuPosition = function () {
* // Example of a BookletLayout that contains two PageLayouts.
*
* function PageOneLayout( name, config ) {
- * PageOneLayout.super.call( this, name, config );
+ * PageOneLayout.parent.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 );
@@ -8777,7 +9667,7 @@ OO.ui.MenuLayout.prototype.getMenuPosition = function () {
* };
*
* function PageTwoLayout( name, config ) {
- * PageTwoLayout.super.call( this, name, config );
+ * PageTwoLayout.parent.call( this, name, config );
* this.$element.append( '<p>Second page</p>' );
* }
* OO.inheritClass( PageTwoLayout, OO.ui.PageLayout );
@@ -8810,7 +9700,7 @@ OO.ui.BookletLayout = function OoUiBookletLayout( config ) {
config = config || {};
// Parent constructor
- OO.ui.BookletLayout.super.call( this, config );
+ OO.ui.BookletLayout.parent.call( this, config );
// Properties
this.currentPageName = null;
@@ -8936,7 +9826,7 @@ OO.ui.BookletLayout.prototype.onStackLayoutSet = function ( page ) {
* @param {number} [itemIndex] A specific item to focus on
*/
OO.ui.BookletLayout.prototype.focus = function ( itemIndex ) {
- var $input, page,
+ var page,
items = this.stackLayout.getItems();
if ( itemIndex !== undefined && items[ itemIndex ] ) {
@@ -8953,11 +9843,8 @@ OO.ui.BookletLayout.prototype.focus = function ( itemIndex ) {
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();
- }
+ if ( !OO.ui.contains( page.$element[ 0 ], this.getElementDocument().activeElement, true ) ) {
+ page.focus();
}
};
@@ -8966,28 +9853,7 @@ OO.ui.BookletLayout.prototype.focus = function ( itemIndex ) {
* 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 );
- }
+ OO.ui.findFocusable( this.stackLayout.$element ).focus();
};
/**
@@ -9054,7 +9920,7 @@ OO.ui.BookletLayout.prototype.toggleOutline = function ( show ) {
OO.ui.BookletLayout.prototype.getClosestPage = function ( page ) {
var next, prev, level,
pages = this.stackLayout.getItems(),
- index = $.inArray( page, pages );
+ index = pages.indexOf( page );
if ( index !== -1 ) {
next = pages[ index + 1 ];
@@ -9154,7 +10020,7 @@ OO.ui.BookletLayout.prototype.addPages = function ( pages, index ) {
if ( Object.prototype.hasOwnProperty.call( this.pages, name ) ) {
// Correct the insertion index
- currentIndex = $.inArray( this.pages[ name ], stackLayoutPages );
+ currentIndex = stackLayoutPages.indexOf( this.pages[ name ] );
if ( currentIndex !== -1 && currentIndex + 1 < index ) {
index--;
}
@@ -9255,7 +10121,8 @@ OO.ui.BookletLayout.prototype.clearPages = function () {
OO.ui.BookletLayout.prototype.setPage = function ( name ) {
var selectedItem,
$focused,
- page = this.pages[ name ];
+ page = this.pages[ name ],
+ previousPage = this.currentPageName && this.pages[ this.currentPageName ];
if ( name !== this.currentPageName ) {
if ( this.outlined ) {
@@ -9265,21 +10132,34 @@ OO.ui.BookletLayout.prototype.setPage = function ( name ) {
}
}
if ( page ) {
- 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' );
+ if ( previousPage ) {
+ previousPage.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 the layout is non-continuous, this check is
+ // meaningless because the next page is not visible yet and thus can't hold focus.
+ if (
+ this.autoFocus &&
+ this.stackLayout.continuous &&
+ OO.ui.findFocusable( page.$element ).length !== 0
+ ) {
+ $focused = previousPage.$element.find( ':focus' );
if ( $focused.length ) {
$focused[ 0 ].blur();
}
}
}
this.currentPageName = name;
- this.stackLayout.setItem( page );
page.setActive( true );
+ this.stackLayout.setItem( page );
+ if ( !this.stackLayout.continuous && previousPage ) {
+ // This should not be necessary, since any inputs on the previous page should have been
+ // blurred when it was hidden, but browsers are not very consistent about this.
+ $focused = previousPage.$element.find( ':focus' );
+ if ( $focused.length ) {
+ $focused[ 0 ].blur();
+ }
+ }
this.emit( 'set', page );
}
}
@@ -9311,25 +10191,18 @@ OO.ui.BookletLayout.prototype.selectFirstSelectablePage = function () {
* // Example of a IndexLayout that contains two CardLayouts.
*
* function CardOneLayout( name, config ) {
- * CardOneLayout.super.call( this, name, config );
+ * CardOneLayout.parent.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' );
+ * this.tabItem.setLabel( 'Card one' );
* };
*
* var card1 = new CardOneLayout( 'one' ),
- * card2 = new CardTwoLayout( 'two' );
+ * card2 = new CardLayout( 'two', { label: 'Card two' } );
+ *
+ * card2.$element.append( '<p>Second card</p>' );
*
* var index = new OO.ui.IndexLayout();
*
@@ -9342,6 +10215,7 @@ OO.ui.BookletLayout.prototype.selectFirstSelectablePage = function () {
* @constructor
* @param {Object} [config] Configuration options
* @cfg {boolean} [continuous=false] Show all cards, one after another
+ * @cfg {boolean} [expanded=true] Expand the content panel to fill the entire parent element.
* @cfg {boolean} [autoFocus=true] Focus on the first focusable element when a new card is displayed.
*/
OO.ui.IndexLayout = function OoUiIndexLayout( config ) {
@@ -9349,13 +10223,16 @@ OO.ui.IndexLayout = function OoUiIndexLayout( config ) {
config = $.extend( {}, config, { menuPosition: 'top' } );
// Parent constructor
- OO.ui.IndexLayout.super.call( this, config );
+ OO.ui.IndexLayout.parent.call( this, config );
// Properties
this.currentCardName = null;
this.cards = {};
this.ignoreFocus = false;
- this.stackLayout = new OO.ui.StackLayout( { continuous: !!config.continuous } );
+ this.stackLayout = new OO.ui.StackLayout( {
+ continuous: !!config.continuous,
+ expanded: config.expanded
+ } );
this.$content.append( this.stackLayout.$element );
this.autoFocus = config.autoFocus === undefined || !!config.autoFocus;
@@ -9456,7 +10333,7 @@ OO.ui.IndexLayout.prototype.onStackLayoutSet = function ( card ) {
* @param {number} [itemIndex] A specific item to focus on
*/
OO.ui.IndexLayout.prototype.focus = function ( itemIndex ) {
- var $input, card,
+ var card,
items = this.stackLayout.getItems();
if ( itemIndex !== undefined && items[ itemIndex ] ) {
@@ -9472,12 +10349,9 @@ OO.ui.IndexLayout.prototype.focus = function ( itemIndex ) {
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();
- }
+ // Only change the focus if is not already in the current page
+ if ( !OO.ui.contains( card.$element[ 0 ], this.getElementDocument().activeElement, true ) ) {
+ card.focus();
}
};
@@ -9486,27 +10360,7 @@ OO.ui.IndexLayout.prototype.focus = function ( itemIndex ) {
* 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;
- }
- };
-
- 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 );
- }
+ OO.ui.findFocusable( this.stackLayout.$element ).focus();
};
/**
@@ -9530,7 +10384,7 @@ OO.ui.IndexLayout.prototype.onTabSelectWidgetSelect = function ( item ) {
OO.ui.IndexLayout.prototype.getClosestCard = function ( card ) {
var next, prev, level,
cards = this.stackLayout.getItems(),
- index = $.inArray( card, cards );
+ index = cards.indexOf( card );
if ( index !== -1 ) {
next = cards[ index + 1 ];
@@ -9615,7 +10469,7 @@ OO.ui.IndexLayout.prototype.addCards = function ( cards, index ) {
if ( Object.prototype.hasOwnProperty.call( this.cards, name ) ) {
// Correct the insertion index
- currentIndex = $.inArray( this.cards[ name ], stackLayoutCards );
+ currentIndex = stackLayoutCards.indexOf( this.cards[ name ] );
if ( currentIndex !== -1 && currentIndex + 1 < index ) {
index--;
}
@@ -9710,7 +10564,8 @@ OO.ui.IndexLayout.prototype.clearCards = function () {
OO.ui.IndexLayout.prototype.setCard = function ( name ) {
var selectedItem,
$focused,
- card = this.cards[ name ];
+ card = this.cards[ name ],
+ previousCard = this.currentCardName && this.cards[ this.currentCardName ];
if ( name !== this.currentCardName ) {
selectedItem = this.tabSelectWidget.getSelectedItem();
@@ -9718,21 +10573,34 @@ OO.ui.IndexLayout.prototype.setCard = function ( 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 ( previousCard ) {
+ previousCard.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 the layout is non-continuous, this check is
+ // meaningless because the next card is not visible yet and thus can't hold focus.
+ if (
+ this.autoFocus &&
+ this.stackLayout.continuous &&
+ OO.ui.findFocusable( card.$element ).length !== 0
+ ) {
+ $focused = previousCard.$element.find( ':focus' );
if ( $focused.length ) {
$focused[ 0 ].blur();
}
}
}
this.currentCardName = name;
- this.stackLayout.setItem( card );
card.setActive( true );
+ this.stackLayout.setItem( card );
+ if ( !this.stackLayout.continuous && previousCard ) {
+ // This should not be necessary, since any inputs on the previous card should have been
+ // blurred when it was hidden, but browsers are not very consistent about this.
+ $focused = previousCard.$element.find( ':focus' );
+ if ( $focused.length ) {
+ $focused[ 0 ].blur();
+ }
+ }
this.emit( 'set', card );
}
}
@@ -9785,7 +10653,7 @@ OO.ui.PanelLayout = function OoUiPanelLayout( config ) {
}, config );
// Parent constructor
- OO.ui.PanelLayout.super.call( this, config );
+ OO.ui.PanelLayout.parent.call( this, config );
// Initialization
this.$element.addClass( 'oo-ui-panelLayout' );
@@ -9807,6 +10675,17 @@ OO.ui.PanelLayout = function OoUiPanelLayout( config ) {
OO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout );
+/* Methods */
+
+/**
+ * Focus the panel layout
+ *
+ * The default implementation just focuses the first focusable element in the panel
+ */
+OO.ui.PanelLayout.prototype.focus = function () {
+ OO.ui.findFocusable( this.$element ).focus();
+};
+
/**
* 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,
@@ -9822,6 +10701,7 @@ OO.inheritClass( OO.ui.PanelLayout, OO.ui.Layout );
* @constructor
* @param {string} name Unique symbolic name of card
* @param {Object} [config] Configuration options
+ * @cfg {jQuery|string|Function|OO.ui.HtmlSnippet} [label] Label for card's tab
*/
OO.ui.CardLayout = function OoUiCardLayout( name, config ) {
// Allow passing positional parameters inside the config object
@@ -9834,10 +10714,11 @@ OO.ui.CardLayout = function OoUiCardLayout( name, config ) {
config = $.extend( { scrollable: true }, config );
// Parent constructor
- OO.ui.CardLayout.super.call( this, config );
+ OO.ui.CardLayout.parent.call( this, config );
// Properties
this.name = name;
+ this.label = config.label;
this.tabItem = null;
this.active = false;
@@ -9923,6 +10804,9 @@ OO.ui.CardLayout.prototype.setTabItem = function ( tabItem ) {
* @chainable
*/
OO.ui.CardLayout.prototype.setupTabItem = function () {
+ if ( this.label ) {
+ this.tabItem.setLabel( this.label );
+ }
return this;
};
@@ -9973,7 +10857,7 @@ OO.ui.PageLayout = function OoUiPageLayout( name, config ) {
config = $.extend( { scrollable: true }, config );
// Parent constructor
- OO.ui.PageLayout.super.call( this, config );
+ OO.ui.PageLayout.parent.call( this, config );
// Properties
this.name = name;
@@ -10111,7 +10995,7 @@ OO.ui.PageLayout.prototype.setActive = function ( active ) {
*
* @class
* @extends OO.ui.PanelLayout
- * @mixins OO.ui.GroupElement
+ * @mixins OO.ui.mixin.GroupElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -10123,10 +11007,10 @@ OO.ui.StackLayout = function OoUiStackLayout( config ) {
config = $.extend( { scrollable: true }, config );
// Parent constructor
- OO.ui.StackLayout.super.call( this, config );
+ OO.ui.StackLayout.parent.call( this, config );
// Mixin constructors
- OO.ui.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
+ OO.ui.mixin.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
// Properties
this.currentItem = null;
@@ -10145,7 +11029,7 @@ OO.ui.StackLayout = function OoUiStackLayout( config ) {
/* Setup */
OO.inheritClass( OO.ui.StackLayout, OO.ui.PanelLayout );
-OO.mixinClass( OO.ui.StackLayout, OO.ui.GroupElement );
+OO.mixinClass( OO.ui.StackLayout, OO.ui.mixin.GroupElement );
/* Events */
@@ -10201,7 +11085,7 @@ OO.ui.StackLayout.prototype.addItems = function ( items, index ) {
this.updateHiddenState( items, this.currentItem );
// Mixin method
- OO.ui.GroupElement.prototype.addItems.call( this, items, index );
+ OO.ui.mixin.GroupElement.prototype.addItems.call( this, items, index );
if ( !this.currentItem && items.length ) {
this.setItem( items[ 0 ] );
@@ -10222,9 +11106,9 @@ OO.ui.StackLayout.prototype.addItems = function ( items, index ) {
*/
OO.ui.StackLayout.prototype.removeItems = function ( items ) {
// Mixin method
- OO.ui.GroupElement.prototype.removeItems.call( this, items );
+ OO.ui.mixin.GroupElement.prototype.removeItems.call( this, items );
- if ( $.inArray( this.currentItem, items ) !== -1 ) {
+ if ( items.indexOf( this.currentItem ) !== -1 ) {
if ( this.items.length ) {
this.setItem( this.items[ 0 ] );
} else {
@@ -10246,7 +11130,7 @@ OO.ui.StackLayout.prototype.removeItems = function ( items ) {
*/
OO.ui.StackLayout.prototype.clearItems = function () {
this.unsetCurrentItem();
- OO.ui.GroupElement.prototype.clearItems.call( this );
+ OO.ui.mixin.GroupElement.prototype.clearItems.call( this );
return this;
};
@@ -10264,7 +11148,7 @@ OO.ui.StackLayout.prototype.setItem = function ( item ) {
if ( item !== this.currentItem ) {
this.updateHiddenState( this.items, item );
- if ( $.inArray( item, this.items ) !== -1 ) {
+ if ( this.items.indexOf( item ) !== -1 ) {
this.currentItem = item;
this.emit( 'set', item );
} else {
@@ -10301,7 +11185,141 @@ OO.ui.StackLayout.prototype.updateHiddenState = function ( items, selectedItem )
};
/**
- * Horizontal bar layout of tools as icon buttons.
+ * HorizontalLayout arranges its contents in a single line (using `display: inline-block` for its
+ * items), with small margins between them. Convenient when you need to put a number of block-level
+ * widgets on a single line next to each other.
+ *
+ * Note that inline elements, such as OO.ui.ButtonWidgets, do not need this wrapper.
+ *
+ * @example
+ * // HorizontalLayout with a text input and a label
+ * var layout = new OO.ui.HorizontalLayout( {
+ * items: [
+ * new OO.ui.LabelWidget( { label: 'Label' } ),
+ * new OO.ui.TextInputWidget( { value: 'Text' } )
+ * ]
+ * } );
+ * $( 'body' ).append( layout.$element );
+ *
+ * @class
+ * @extends OO.ui.Layout
+ * @mixins OO.ui.mixin.GroupElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {OO.ui.Widget[]|OO.ui.Layout[]} [items] Widgets or other layouts to add to the layout.
+ */
+OO.ui.HorizontalLayout = function OoUiHorizontalLayout( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.HorizontalLayout.parent.call( this, config );
+
+ // Mixin constructors
+ OO.ui.mixin.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
+
+ // Initialization
+ this.$element.addClass( 'oo-ui-horizontalLayout' );
+ if ( Array.isArray( config.items ) ) {
+ this.addItems( config.items );
+ }
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.HorizontalLayout, OO.ui.Layout );
+OO.mixinClass( OO.ui.HorizontalLayout, OO.ui.mixin.GroupElement );
+
+/**
+ * BarToolGroups are one of three types of {@link OO.ui.ToolGroup toolgroups} that are used to
+ * create {@link OO.ui.Toolbar toolbars} (the other types of groups are {@link OO.ui.MenuToolGroup MenuToolGroup}
+ * and {@link OO.ui.ListToolGroup ListToolGroup}). The {@link OO.ui.Tool tools} in a BarToolGroup are
+ * displayed by icon in a single row. The title of the tool is displayed when users move the mouse over
+ * the tool.
+ *
+ * BarToolGroups are created by a {@link OO.ui.ToolGroupFactory tool group factory} when the toolbar is
+ * set up.
+ *
+ * @example
+ * // Example of a BarToolGroup with two tools
+ * 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( 'Example of a BarToolGroup with two tools.' );
+ *
+ * // Define the tools that we're going to place in our toolbar
+ *
+ * // Create a class inheriting from OO.ui.Tool
+ * function PictureTool() {
+ * PictureTool.parent.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 );
+ *
+ * // 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 by icon only
+ * type: 'bar',
+ * include: [ 'picture', 'help' ]
+ * }
+ * ] );
+ *
+ * // 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();
+ *
+ * For more information about how to add tools to a bar tool group, please see {@link OO.ui.ToolGroup toolgroup}.
+ * For more information about toolbars in general, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Toolbars
*
* @class
* @extends OO.ui.ToolGroup
@@ -10318,7 +11336,7 @@ OO.ui.BarToolGroup = function OoUiBarToolGroup( toolbar, config ) {
}
// Parent constructor
- OO.ui.BarToolGroup.super.call( this, toolbar, config );
+ OO.ui.BarToolGroup.parent.call( this, toolbar, config );
// Initialization
this.$element.addClass( 'oo-ui-barToolGroup' );
@@ -10337,22 +11355,24 @@ OO.ui.BarToolGroup.static.accelTooltips = true;
OO.ui.BarToolGroup.static.name = 'bar';
/**
- * Popup list of tools with an icon and optional label.
+ * PopupToolGroup is an abstract base class used by both {@link OO.ui.MenuToolGroup MenuToolGroup}
+ * and {@link OO.ui.ListToolGroup ListToolGroup} to provide a popup--an overlaid menu or list of tools with an
+ * optional icon and label. This class can be used for other base classes that also use this functionality.
*
* @abstract
* @class
* @extends OO.ui.ToolGroup
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.TitledElement
- * @mixins OO.ui.ClippableElement
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.IndicatorElement
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.TitledElement
+ * @mixins OO.ui.mixin.ClippableElement
+ * @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
* @param {OO.ui.Toolbar} toolbar
* @param {Object} [config] Configuration options
- * @cfg {string} [header] Text to display at the top of the pop-up
+ * @cfg {string} [header] Text to display at the top of the popup
*/
OO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {
// Allow passing positional parameters inside the config object
@@ -10365,7 +11385,7 @@ OO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {
config = config || {};
// Parent constructor
- OO.ui.PopupToolGroup.super.call( this, toolbar, config );
+ OO.ui.PopupToolGroup.parent.call( this, toolbar, config );
// Properties
this.active = false;
@@ -10374,12 +11394,12 @@ OO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {
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 } ) );
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$handle } ) );
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.IndicatorElement.call( this, config );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.TitledElement.call( this, config );
+ OO.ui.mixin.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$group } ) );
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$handle } ) );
// Events
this.$handle.on( {
@@ -10411,12 +11431,12 @@ OO.ui.PopupToolGroup = function OoUiPopupToolGroup( toolbar, config ) {
/* Setup */
OO.inheritClass( OO.ui.PopupToolGroup, OO.ui.ToolGroup );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.IconElement );
-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 );
-OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.TabIndexedElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.TitledElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.ClippableElement );
+OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.mixin.TabIndexedElement );
/* Methods */
@@ -10425,7 +11445,7 @@ OO.mixinClass( OO.ui.PopupToolGroup, OO.ui.TabIndexedElement );
*/
OO.ui.PopupToolGroup.prototype.setDisabled = function () {
// Parent method
- OO.ui.PopupToolGroup.super.prototype.setDisabled.apply( this, arguments );
+ OO.ui.PopupToolGroup.parent.prototype.setDisabled.apply( this, arguments );
if ( this.isDisabled() && this.isElementAttached() ) {
this.setActive( false );
@@ -10437,6 +11457,7 @@ OO.ui.PopupToolGroup.prototype.setDisabled = function () {
*
* The event is actually generated from a mouseup/keyup, so it is not a normal blur event object.
*
+ * @protected
* @param {jQuery.Event} e Mouse up or key up event
*/
OO.ui.PopupToolGroup.prototype.onBlur = function ( e ) {
@@ -10457,12 +11478,13 @@ OO.ui.PopupToolGroup.prototype.onMouseKeyUp = function ( e ) {
) {
this.setActive( false );
}
- return OO.ui.PopupToolGroup.super.prototype.onMouseKeyUp.call( this, e );
+ return OO.ui.PopupToolGroup.parent.prototype.onMouseKeyUp.call( this, e );
};
/**
* Handle mouse up and key up events.
*
+ * @protected
* @param {jQuery.Event} e Mouse up or key up event
*/
OO.ui.PopupToolGroup.prototype.onHandleMouseKeyUp = function ( e ) {
@@ -10477,6 +11499,7 @@ OO.ui.PopupToolGroup.prototype.onHandleMouseKeyUp = function ( e ) {
/**
* Handle mouse down and key down events.
*
+ * @protected
* @param {jQuery.Event} e Mouse down or key down event
*/
OO.ui.PopupToolGroup.prototype.onHandleMouseKeyDown = function ( e ) {
@@ -10490,18 +11513,21 @@ OO.ui.PopupToolGroup.prototype.onHandleMouseKeyDown = function ( e ) {
};
/**
- * Switch into active mode.
+ * Switch into 'active' mode.
*
- * When active, mouseup events anywhere in the document will trigger deactivation.
+ * When active, the popup is visible. A mouseup event anywhere in the document will trigger
+ * deactivation.
*/
OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
+ var containerWidth, containerLeft;
value = !!value;
if ( this.active !== value ) {
this.active = value;
if ( value ) {
- this.getElementDocument().addEventListener( 'mouseup', this.onBlurHandler, true );
- this.getElementDocument().addEventListener( 'keyup', this.onBlurHandler, true );
+ OO.ui.addCaptureEventListener( this.getElementDocument(), 'mouseup', this.onBlurHandler );
+ OO.ui.addCaptureEventListener( this.getElementDocument(), 'keyup', this.onBlurHandler );
+ this.$clippable.css( 'left', '' );
// Try anchoring the popup to the left first
this.$element.addClass( 'oo-ui-popupToolGroup-active oo-ui-popupToolGroup-left' );
this.toggleClipping( true );
@@ -10513,9 +11539,22 @@ OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
.addClass( 'oo-ui-popupToolGroup-right' );
this.toggleClipping( true );
}
+ if ( this.isClippedHorizontally() ) {
+ // Anchoring to the right also caused the popup to clip, so just make it fill the container
+ containerWidth = this.$clippableScrollableContainer.width();
+ containerLeft = this.$clippableScrollableContainer.offset().left;
+
+ this.toggleClipping( false );
+ this.$element.removeClass( 'oo-ui-popupToolGroup-right' );
+
+ this.$clippable.css( {
+ left: -( this.$element.offset().left - containerLeft ),
+ width: containerWidth
+ } );
+ }
} else {
- this.getElementDocument().removeEventListener( 'mouseup', this.onBlurHandler, true );
- this.getElementDocument().removeEventListener( 'keyup', this.onBlurHandler, true );
+ OO.ui.removeCaptureEventListener( this.getElementDocument(), 'mouseup', this.onBlurHandler );
+ OO.ui.removeCaptureEventListener( this.getElementDocument(), 'keyup', this.onBlurHandler );
this.$element.removeClass(
'oo-ui-popupToolGroup-active oo-ui-popupToolGroup-left oo-ui-popupToolGroup-right'
);
@@ -10525,11 +11564,79 @@ OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
};
/**
- * Drop down list layout of tools as labeled icon buttons.
+ * ListToolGroups are one of three types of {@link OO.ui.ToolGroup toolgroups} that are used to
+ * create {@link OO.ui.Toolbar toolbars} (the other types of groups are {@link OO.ui.MenuToolGroup MenuToolGroup}
+ * and {@link OO.ui.BarToolGroup BarToolGroup}). The {@link OO.ui.Tool tools} in a ListToolGroup are displayed
+ * by label in a dropdown menu. The title of the tool is used as the label text. The menu itself can be configured
+ * with a label, icon, indicator, header, and title.
+ *
+ * ListToolGroups can be configured to be expanded and collapsed. Collapsed lists will have a ‘More’ option that
+ * users can select to see the full list of tools. If a collapsed toolgroup is expanded, a ‘Fewer’ option permits
+ * users to collapse the list again.
*
- * 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.
+ * ListToolGroups are created by a {@link OO.ui.ToolGroupFactory toolgroup factory} when the toolbar is set up. The factory
+ * requires the ListToolGroup's symbolic name, 'list', which is specified along with the other configurations. For more
+ * information about how to add tools to a ListToolGroup, please see {@link OO.ui.ToolGroup toolgroup}.
+ *
+ * @example
+ * // Example of a ListToolGroup
+ * var toolFactory = new OO.ui.ToolFactory();
+ * var toolGroupFactory = new OO.ui.ToolGroupFactory();
+ * var toolbar = new OO.ui.Toolbar( toolFactory, toolGroupFactory );
+ *
+ * // Configure and register two tools
+ * function SettingsTool() {
+ * SettingsTool.parent.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 () {
+ * this.setActive( false );
+ * };
+ * toolFactory.register( SettingsTool );
+ * // Register two more tools, nothing interesting here
+ * function StuffTool() {
+ * StuffTool.parent.apply( this, arguments );
+ * }
+ * OO.inheritClass( StuffTool, OO.ui.Tool );
+ * StuffTool.static.name = 'stuff';
+ * StuffTool.static.icon = 'ellipsis';
+ * StuffTool.static.title = 'Change the world';
+ * StuffTool.prototype.onSelect = function () {
+ * this.setActive( false );
+ * };
+ * toolFactory.register( StuffTool );
+ * toolbar.setup( [
+ * {
+ * // Configurations for list toolgroup.
+ * type: 'list',
+ * label: 'ListToolGroup',
+ * indicator: 'down',
+ * icon: 'picture',
+ * title: 'This is the title, displayed when user moves the mouse over the list toolgroup',
+ * header: 'This is the header',
+ * include: [ 'settings', 'stuff' ],
+ * allowCollapse: ['stuff']
+ * }
+ * ] );
+ *
+ * // Create some UI around the toolbar and place it in the document
+ * var frame = new OO.ui.PanelLayout( {
+ * expanded: false,
+ * framed: true
+ * } );
+ * frame.$element.append(
+ * toolbar.$element
+ * );
+ * $( 'body' ).append( frame.$element );
+ * // Build the toolbar. This must be done after the toolbar has been appended to the document.
+ * toolbar.initialize();
+ *
+ * For more information about toolbars in general, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Toolbars
*
* @class
* @extends OO.ui.PopupToolGroup
@@ -10537,11 +11644,16 @@ OO.ui.PopupToolGroup.prototype.setActive = function ( value ) {
* @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
+ * @cfg {Array} [allowCollapse] Allow the specified tools to be collapsed. By default, collapsible tools
+ * will only be displayed if users click the ‘More’ option displayed at the bottom of the list. If
+ * the list is expanded, a ‘Fewer’ option permits users to collapse the list again. Any tools that
+ * are included in the toolgroup, but are not designated as collapsible, will always be displayed.
+ * To open a collapsible list in its expanded state, set #expanded to 'true'.
+ * @cfg {Array} [forceExpand] Expand the specified tools. All other tools will be designated as collapsible.
+ * Unless #expanded is set to true, the collapsible tools will be collapsed when the list is first opened.
+ * @cfg {boolean} [expanded=false] Expand collapsible tools. This config is only relevant if tools have
+ * been designated as collapsible. When expanded is set to true, all tools in the group will be displayed
+ * when the list is first opened. Users can collapse the list with a ‘Fewer’ option at the bottom.
*/
OO.ui.ListToolGroup = function OoUiListToolGroup( toolbar, config ) {
// Allow passing positional parameters inside the config object
@@ -10560,7 +11672,7 @@ OO.ui.ListToolGroup = function OoUiListToolGroup( toolbar, config ) {
this.collapsibleTools = [];
// Parent constructor
- OO.ui.ListToolGroup.super.call( this, toolbar, config );
+ OO.ui.ListToolGroup.parent.call( this, toolbar, config );
// Initialization
this.$element.addClass( 'oo-ui-listToolGroup' );
@@ -10582,7 +11694,7 @@ OO.ui.ListToolGroup.static.name = 'list';
OO.ui.ListToolGroup.prototype.populate = function () {
var i, len, allowCollapse = [];
- OO.ui.ListToolGroup.super.prototype.populate.call( this );
+ OO.ui.ListToolGroup.parent.prototype.populate.call( this );
// Update the list of collapsible tools
if ( this.allowCollapse !== undefined ) {
@@ -10606,9 +11718,10 @@ OO.ui.ListToolGroup.prototype.populate = function () {
};
OO.ui.ListToolGroup.prototype.getExpandCollapseTool = function () {
+ var ExpandCollapseTool;
if ( this.expandCollapseTool === undefined ) {
- var ExpandCollapseTool = function () {
- ExpandCollapseTool.super.apply( this, arguments );
+ ExpandCollapseTool = function () {
+ ExpandCollapseTool.parent.apply( this, arguments );
};
OO.inheritClass( ExpandCollapseTool, OO.ui.Tool );
@@ -10640,9 +11753,9 @@ OO.ui.ListToolGroup.prototype.onMouseKeyUp = function ( e ) {
) {
// 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 );
+ return OO.ui.ListToolGroup.parent.parent.prototype.onMouseKeyUp.call( this, e );
} else {
- return OO.ui.ListToolGroup.super.prototype.onMouseKeyUp.call( this, e );
+ return OO.ui.ListToolGroup.parent.prototype.onMouseKeyUp.call( this, e );
}
};
@@ -10659,7 +11772,104 @@ OO.ui.ListToolGroup.prototype.updateCollapsibleState = function () {
};
/**
- * Drop down menu layout of tools as selectable menu items.
+ * MenuToolGroups are one of three types of {@link OO.ui.ToolGroup toolgroups} that are used to
+ * create {@link OO.ui.Toolbar toolbars} (the other types of groups are {@link OO.ui.BarToolGroup BarToolGroup}
+ * and {@link OO.ui.ListToolGroup ListToolGroup}). MenuToolGroups contain selectable {@link OO.ui.Tool tools},
+ * which are displayed by label in a dropdown menu. The tool's title is used as the label text, and the
+ * menu label is updated to reflect which tool or tools are currently selected. If no tools are selected,
+ * the menu label is empty. The menu can be configured with an indicator, icon, title, and/or header.
+ *
+ * MenuToolGroups are created by a {@link OO.ui.ToolGroupFactory tool group factory} when the toolbar
+ * is set up. Note that all tools must define an {@link OO.ui.Tool#onUpdateState onUpdateState} method if
+ * a MenuToolGroup is used.
+ *
+ * @example
+ * // Example of a MenuToolGroup
+ * 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( 'An example of a MenuToolGroup. Select a tool from the dropdown menu.' );
+ *
+ * // Define the tools that we're going to place in our toolbar
+ *
+ * function SettingsTool() {
+ * SettingsTool.parent.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 );
+ *
+ * function StuffTool() {
+ * StuffTool.parent.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 );
+ *
+ * // 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( [
+ * {
+ * type: 'menu',
+ * header: 'This is the (optional) header',
+ * title: 'This is the (optional) title',
+ * 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' );
+ *
+ * For more information about how to add tools to a MenuToolGroup, please see {@link OO.ui.ToolGroup toolgroup}.
+ * For more information about toolbars in general, please see the [OOjs UI documentation on MediaWiki] [1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Toolbars
*
* @class
* @extends OO.ui.PopupToolGroup
@@ -10679,7 +11889,7 @@ OO.ui.MenuToolGroup = function OoUiMenuToolGroup( toolbar, config ) {
config = config || {};
// Parent constructor
- OO.ui.MenuToolGroup.super.call( this, toolbar, config );
+ OO.ui.MenuToolGroup.parent.call( this, toolbar, config );
// Events
this.toolbar.connect( this, { updateState: 'onUpdateState' } );
@@ -10703,6 +11913,8 @@ OO.ui.MenuToolGroup.static.name = 'menu';
*
* When the state changes, the title of each active item in the menu will be joined together and
* used as a label for the group. The label will be empty if none of the items are active.
+ *
+ * @private
*/
OO.ui.MenuToolGroup.prototype.onUpdateState = function () {
var name,
@@ -10718,12 +11930,35 @@ OO.ui.MenuToolGroup.prototype.onUpdateState = function () {
};
/**
- * Tool that shows a popup when selected.
+ * Popup tools open a popup window when they are selected from the {@link OO.ui.Toolbar toolbar}. Each popup tool is configured
+ * with a static name, title, and icon, as well with as any popup configurations. Unlike other tools, popup tools do not require that developers specify
+ * an #onSelect or #onUpdateState method, as these methods have been implemented already.
+ *
+ * // Example of a popup tool. When selected, a popup tool displays
+ * // a popup window.
+ * 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 );
+ *
+ * For an example of a toolbar that contains a popup tool, see {@link OO.ui.Toolbar toolbars}. For more information about
+ * toolbars in genreral, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Toolbars
*
* @abstract
* @class
* @extends OO.ui.Tool
- * @mixins OO.ui.PopupElement
+ * @mixins OO.ui.mixin.PopupElement
*
* @constructor
* @param {OO.ui.ToolGroup} toolGroup
@@ -10737,10 +11972,10 @@ OO.ui.PopupTool = function OoUiPopupTool( toolGroup, config ) {
}
// Parent constructor
- OO.ui.PopupTool.super.call( this, toolGroup, config );
+ OO.ui.PopupTool.parent.call( this, toolGroup, config );
// Mixin constructors
- OO.ui.PopupElement.call( this, config );
+ OO.ui.mixin.PopupElement.call( this, config );
// Initialization
this.$element
@@ -10751,7 +11986,7 @@ OO.ui.PopupTool = function OoUiPopupTool( toolGroup, config ) {
/* Setup */
OO.inheritClass( OO.ui.PopupTool, OO.ui.Tool );
-OO.mixinClass( OO.ui.PopupTool, OO.ui.PopupElement );
+OO.mixinClass( OO.ui.PopupTool, OO.ui.mixin.PopupElement );
/* Methods */
@@ -10778,8 +12013,33 @@ 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).
+ * A ToolGroupTool is a special sort of tool that can contain other {@link OO.ui.Tool tools}
+ * and {@link OO.ui.ToolGroup toolgroups}. The ToolGroupTool was specifically designed to be used
+ * inside a {@link OO.ui.BarToolGroup bar} toolgroup to provide access to additional tools from
+ * the bar item. Included tools will be displayed in a dropdown {@link OO.ui.ListToolGroup list}
+ * when the ToolGroupTool is selected.
+ *
+ * // Example: ToolGroupTool with two nested tools, 'setting1' and 'setting2', defined elsewhere.
+ *
+ * function SettingsTool() {
+ * SettingsTool.parent.apply( this, arguments );
+ * };
+ * OO.inheritClass( SettingsTool, OO.ui.ToolGroupTool );
+ * SettingsTool.static.name = 'settings';
+ * SettingsTool.static.title = 'Change settings';
+ * SettingsTool.static.groupConfig = {
+ * icon: 'settings',
+ * label: 'ToolGroupTool',
+ * include: [ 'setting1', 'setting2' ]
+ * };
+ * toolFactory.register( SettingsTool );
+ *
+ * For more information, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * Please note that this implementation is subject to change per [T74159] [2].
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Toolbars#ToolGroupTool
+ * [2]: https://phabricator.wikimedia.org/T74159
*
* @abstract
* @class
@@ -10797,7 +12057,7 @@ OO.ui.ToolGroupTool = function OoUiToolGroupTool( toolGroup, config ) {
}
// Parent constructor
- OO.ui.ToolGroupTool.super.call( this, toolGroup, config );
+ OO.ui.ToolGroupTool.parent.call( this, toolGroup, config );
// Properties
this.innerToolGroup = this.createGroup( this.constructor.static.groupConfig );
@@ -10819,7 +12079,11 @@ OO.inheritClass( OO.ui.ToolGroupTool, OO.ui.Tool );
/* Static Properties */
/**
- * Tool group configuration. See OO.ui.Toolbar#setup for the accepted values.
+ * Toolgroup configuration.
+ *
+ * The toolgroup configuration consists of the tools to include, as well as an icon and label
+ * to use for the bar item. Tools can be included by symbolic name, group, or with the
+ * wildcard selector. Please see {@link OO.ui.ToolGroup toolgroup} for more information.
*
* @property {Object.<string,Array>}
*/
@@ -10857,10 +12121,10 @@ OO.ui.ToolGroupTool.prototype.onUpdateState = function () {
};
/**
- * Build a OO.ui.ToolGroup from the configuration.
+ * Build a {@link OO.ui.ToolGroup toolgroup} from the specified configuration.
*
- * @param {Object.<string,Array>} group Tool group configuration. See OO.ui.Toolbar#setup for the
- * accepted values.
+ * @param {Object.<string,Array>} group Toolgroup configuration. Please see {@link OO.ui.ToolGroup toolgroup} for
+ * more information.
* @return {OO.ui.ListToolGroup}
*/
OO.ui.ToolGroupTool.prototype.createGroup = function ( group ) {
@@ -10875,26 +12139,26 @@ OO.ui.ToolGroupTool.prototype.createGroup = function ( group ) {
};
/**
- * Mixin for OO.ui.Widget subclasses to provide OO.ui.GroupElement.
+ * Mixin for OO.ui.Widget subclasses to provide OO.ui.mixin.GroupElement.
*
- * Use together with OO.ui.ItemWidget to make disabled state inheritable.
+ * Use together with OO.ui.mixin.ItemWidget to make disabled state inheritable.
*
* @private
* @abstract
* @class
- * @extends OO.ui.GroupElement
+ * @extends OO.ui.mixin.GroupElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
-OO.ui.GroupWidget = function OoUiGroupWidget( config ) {
+OO.ui.mixin.GroupWidget = function OoUiMixinGroupWidget( config ) {
// Parent constructor
- OO.ui.GroupWidget.super.call( this, config );
+ OO.ui.mixin.GroupWidget.parent.call( this, config );
};
/* Setup */
-OO.inheritClass( OO.ui.GroupWidget, OO.ui.GroupElement );
+OO.inheritClass( OO.ui.mixin.GroupWidget, OO.ui.mixin.GroupElement );
/* Methods */
@@ -10906,14 +12170,14 @@ OO.inheritClass( OO.ui.GroupWidget, OO.ui.GroupElement );
* @param {boolean} disabled Disable widget
* @chainable
*/
-OO.ui.GroupWidget.prototype.setDisabled = function ( disabled ) {
+OO.ui.mixin.GroupWidget.prototype.setDisabled = function ( disabled ) {
var i, len;
// Parent method
// Note: Calling #setDisabled this way assumes this is mixed into an OO.ui.Widget
OO.ui.Widget.prototype.setDisabled.call( this, disabled );
- // During construction, #setDisabled is called before the OO.ui.GroupElement constructor
+ // During construction, #setDisabled is called before the OO.ui.mixin.GroupElement constructor
if ( this.items ) {
for ( i = 0, len = this.items.length; i < len; i++ ) {
this.items[ i ].updateDisabled();
@@ -10924,12 +12188,12 @@ OO.ui.GroupWidget.prototype.setDisabled = function ( disabled ) {
};
/**
- * Mixin for widgets used as items in widgets that inherit OO.ui.GroupWidget.
+ * Mixin for widgets used as items in widgets that mix in OO.ui.mixin.GroupWidget.
*
- * Item widgets have a reference to a OO.ui.GroupWidget while they are attached to the group. This
+ * Item widgets have a reference to a OO.ui.mixin.GroupWidget while they are attached to the group. This
* allows bidirectional communication.
*
- * Use together with OO.ui.GroupWidget to make disabled state inheritable.
+ * Use together with OO.ui.mixin.GroupWidget to make disabled state inheritable.
*
* @private
* @abstract
@@ -10937,7 +12201,7 @@ OO.ui.GroupWidget.prototype.setDisabled = function ( disabled ) {
*
* @constructor
*/
-OO.ui.ItemWidget = function OoUiItemWidget() {
+OO.ui.mixin.ItemWidget = function OoUiMixinItemWidget() {
//
};
@@ -10950,7 +12214,7 @@ OO.ui.ItemWidget = function OoUiItemWidget() {
*
* @return {boolean} Widget is disabled
*/
-OO.ui.ItemWidget.prototype.isDisabled = function () {
+OO.ui.mixin.ItemWidget.prototype.isDisabled = function () {
return this.disabled ||
( this.elementGroup instanceof OO.ui.Widget && this.elementGroup.isDisabled() );
};
@@ -10958,10 +12222,10 @@ OO.ui.ItemWidget.prototype.isDisabled = function () {
/**
* Set group element is in.
*
- * @param {OO.ui.GroupElement|null} group Group element, null if none
+ * @param {OO.ui.mixin.GroupElement|null} group Group element, null if none
* @chainable
*/
-OO.ui.ItemWidget.prototype.setElementGroup = function ( group ) {
+OO.ui.mixin.ItemWidget.prototype.setElementGroup = function ( group ) {
// Parent method
// Note: Calling #setElementGroup this way assumes this is mixed into an OO.ui.Element
OO.ui.Element.prototype.setElementGroup.call( this, group );
@@ -10975,12 +12239,13 @@ OO.ui.ItemWidget.prototype.setElementGroup = function ( group ) {
/**
* 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}.####
+ *
+ * **Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.**
*
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.GroupElement
- * @mixins OO.ui.IconElement
+ * @mixins OO.ui.mixin.GroupElement
+ * @mixins OO.ui.mixin.IconElement
*
* @constructor
* @param {OO.ui.OutlineSelectWidget} outline Outline to control
@@ -11000,11 +12265,11 @@ OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, confi
config = $.extend( { icon: 'add' }, config );
// Parent constructor
- OO.ui.OutlineControlsWidget.super.call( this, config );
+ OO.ui.OutlineControlsWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.GroupElement.call( this, config );
- OO.ui.IconElement.call( this, config );
+ OO.ui.mixin.GroupElement.call( this, config );
+ OO.ui.mixin.IconElement.call( this, config );
// Properties
this.outline = outline;
@@ -11049,8 +12314,8 @@ OO.ui.OutlineControlsWidget = function OoUiOutlineControlsWidget( outline, confi
/* Setup */
OO.inheritClass( OO.ui.OutlineControlsWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.GroupElement );
-OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.IconElement );
+OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.mixin.GroupElement );
+OO.mixinClass( OO.ui.OutlineControlsWidget, OO.ui.mixin.IconElement );
/* Events */
@@ -11076,8 +12341,8 @@ OO.ui.OutlineControlsWidget.prototype.setAbilities = function ( abilities ) {
var ability;
for ( ability in this.abilities ) {
- if ( abilities[ability] !== undefined ) {
- this.abilities[ability] = !!abilities[ability];
+ if ( abilities[ ability ] !== undefined ) {
+ this.abilities[ ability ] = !!abilities[ ability ];
}
}
@@ -11085,7 +12350,6 @@ OO.ui.OutlineControlsWidget.prototype.setAbilities = function ( abilities ) {
};
/**
- *
* @private
* Handle outline change events.
*/
@@ -11136,7 +12400,7 @@ OO.ui.ToggleWidget = function OoUiToggleWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.ToggleWidget.super.call( this, config );
+ OO.ui.ToggleWidget.parent.call( this, config );
// Properties
this.value = null;
@@ -11216,7 +12480,7 @@ OO.ui.ToggleWidget.prototype.setValue = function ( value ) {
*
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.GroupElement
+ * @mixins OO.ui.mixin.GroupElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -11227,10 +12491,10 @@ OO.ui.ButtonGroupWidget = function OoUiButtonGroupWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.ButtonGroupWidget.super.call( this, config );
+ OO.ui.ButtonGroupWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
+ OO.ui.mixin.GroupElement.call( this, $.extend( {}, config, { $group: this.$element } ) );
// Initialization
this.$element.addClass( 'oo-ui-buttonGroupWidget' );
@@ -11242,7 +12506,7 @@ OO.ui.ButtonGroupWidget = function OoUiButtonGroupWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.ButtonGroupWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.GroupElement );
+OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.mixin.GroupElement );
/**
* ButtonWidget is a generic widget for buttons. A wide variety of looks,
@@ -11265,13 +12529,14 @@ OO.mixinClass( OO.ui.ButtonGroupWidget, OO.ui.GroupElement );
*
* @class
* @extends OO.ui.Widget
- * @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
+ * @mixins OO.ui.mixin.ButtonElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.IndicatorElement
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.TitledElement
+ * @mixins OO.ui.mixin.FlaggedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
+ * @mixins OO.ui.mixin.AccessKeyedElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -11284,16 +12549,17 @@ OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.ButtonWidget.super.call( this, config );
+ OO.ui.ButtonWidget.parent.call( this, config );
// Mixin constructors
- 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 } ) );
+ OO.ui.mixin.ButtonElement.call( this, config );
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.IndicatorElement.call( this, config );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.TitledElement.call( this, $.extend( {}, config, { $titled: this.$button } ) );
+ OO.ui.mixin.FlaggedElement.call( this, config );
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$button } ) );
+ OO.ui.mixin.AccessKeyedElement.call( this, $.extend( {}, config, { $accessKeyed: this.$button } ) );
// Properties
this.href = null;
@@ -11316,13 +12582,14 @@ OO.ui.ButtonWidget = function OoUiButtonWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.ButtonWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.ButtonElement );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.IconElement );
-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 );
-OO.mixinClass( OO.ui.ButtonWidget, OO.ui.TabIndexedElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.ButtonElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.TitledElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.FlaggedElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.TabIndexedElement );
+OO.mixinClass( OO.ui.ButtonWidget, OO.ui.mixin.AccessKeyedElement );
/* Methods */
@@ -11335,7 +12602,7 @@ OO.ui.ButtonWidget.prototype.onMouseDown = function ( e ) {
this.$button.removeAttr( 'tabindex' );
}
- return OO.ui.ButtonElement.prototype.onMouseDown.call( this, e );
+ return OO.ui.mixin.ButtonElement.prototype.onMouseDown.call( this, e );
};
/**
@@ -11347,7 +12614,7 @@ OO.ui.ButtonWidget.prototype.onMouseUp = function ( e ) {
this.$button.attr( 'tabindex', this.tabIndex );
}
- return OO.ui.ButtonElement.prototype.onMouseUp.call( this, e );
+ return OO.ui.mixin.ButtonElement.prototype.onMouseUp.call( this, e );
};
/**
@@ -11384,6 +12651,12 @@ OO.ui.ButtonWidget.prototype.getNoFollow = function () {
*/
OO.ui.ButtonWidget.prototype.setHref = function ( href ) {
href = typeof href === 'string' ? href : null;
+ if ( href !== null ) {
+ if ( !OO.ui.isSafeUrl( href ) ) {
+ throw new Error( 'Potentially unsafe href provided: ' + href );
+ }
+
+ }
if ( href !== this.href ) {
this.href = href;
@@ -11473,7 +12746,7 @@ OO.ui.ButtonWidget.prototype.setNoFollow = function ( noFollow ) {
*
* @class
* @extends OO.ui.ButtonWidget
- * @mixins OO.ui.PendingElement
+ * @mixins OO.ui.mixin.PendingElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -11488,10 +12761,10 @@ OO.ui.ActionWidget = function OoUiActionWidget( config ) {
config = $.extend( { framed: false }, config );
// Parent constructor
- OO.ui.ActionWidget.super.call( this, config );
+ OO.ui.ActionWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.PendingElement.call( this, config );
+ OO.ui.mixin.PendingElement.call( this, config );
// Properties
this.action = config.action || '';
@@ -11506,7 +12779,7 @@ OO.ui.ActionWidget = function OoUiActionWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.ActionWidget, OO.ui.ButtonWidget );
-OO.mixinClass( OO.ui.ActionWidget, OO.ui.PendingElement );
+OO.mixinClass( OO.ui.ActionWidget, OO.ui.mixin.PendingElement );
/* Events */
@@ -11578,7 +12851,7 @@ OO.ui.ActionWidget.prototype.propagateResize = function () {
*/
OO.ui.ActionWidget.prototype.setIcon = function () {
// Mixin method
- OO.ui.IconElement.prototype.setIcon.apply( this, arguments );
+ OO.ui.mixin.IconElement.prototype.setIcon.apply( this, arguments );
this.propagateResize();
return this;
@@ -11589,7 +12862,7 @@ OO.ui.ActionWidget.prototype.setIcon = function () {
*/
OO.ui.ActionWidget.prototype.setLabel = function () {
// Mixin method
- OO.ui.LabelElement.prototype.setLabel.apply( this, arguments );
+ OO.ui.mixin.LabelElement.prototype.setLabel.apply( this, arguments );
this.propagateResize();
return this;
@@ -11600,7 +12873,7 @@ OO.ui.ActionWidget.prototype.setLabel = function () {
*/
OO.ui.ActionWidget.prototype.setFlags = function () {
// Mixin method
- OO.ui.FlaggedElement.prototype.setFlags.apply( this, arguments );
+ OO.ui.mixin.FlaggedElement.prototype.setFlags.apply( this, arguments );
this.propagateResize();
return this;
@@ -11611,7 +12884,7 @@ OO.ui.ActionWidget.prototype.setFlags = function () {
*/
OO.ui.ActionWidget.prototype.clearFlags = function () {
// Mixin method
- OO.ui.FlaggedElement.prototype.clearFlags.apply( this, arguments );
+ OO.ui.mixin.FlaggedElement.prototype.clearFlags.apply( this, arguments );
this.propagateResize();
return this;
@@ -11625,7 +12898,7 @@ OO.ui.ActionWidget.prototype.clearFlags = function () {
*/
OO.ui.ActionWidget.prototype.toggle = function () {
// Parent method
- OO.ui.ActionWidget.super.prototype.toggle.apply( this, arguments );
+ OO.ui.ActionWidget.parent.prototype.toggle.apply( this, arguments );
this.propagateResize();
return this;
@@ -11651,17 +12924,17 @@ OO.ui.ActionWidget.prototype.toggle = function () {
*
* @class
* @extends OO.ui.ButtonWidget
- * @mixins OO.ui.PopupElement
+ * @mixins OO.ui.mixin.PopupElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
OO.ui.PopupButtonWidget = function OoUiPopupButtonWidget( config ) {
// Parent constructor
- OO.ui.PopupButtonWidget.super.call( this, config );
+ OO.ui.PopupButtonWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.PopupElement.call( this, config );
+ OO.ui.mixin.PopupElement.call( this, config );
// Events
this.connect( this, { click: 'onAction' } );
@@ -11676,7 +12949,7 @@ OO.ui.PopupButtonWidget = function OoUiPopupButtonWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.PopupButtonWidget, OO.ui.ButtonWidget );
-OO.mixinClass( OO.ui.PopupButtonWidget, OO.ui.PopupElement );
+OO.mixinClass( OO.ui.PopupButtonWidget, OO.ui.mixin.PopupElement );
/* Methods */
@@ -11692,9 +12965,9 @@ OO.ui.PopupButtonWidget.prototype.onAction = function () {
/**
* 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
+ * configured with {@link OO.ui.mixin.IconElement icons}, {@link OO.ui.mixin.IndicatorElement indicators},
+ * {@link OO.ui.mixin.TitledElement titles}, {@link OO.ui.mixin.FlaggedElement styling flags},
+ * and {@link OO.ui.mixin.LabelElement labels}. Please see
* the [OOjs UI documentation][1] on MediaWiki for more information.
*
* @example
@@ -11713,13 +12986,13 @@ OO.ui.PopupButtonWidget.prototype.onAction = function () {
*
* @class
* @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
+ * @mixins OO.ui.mixin.ButtonElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.IndicatorElement
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.TitledElement
+ * @mixins OO.ui.mixin.FlaggedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -11731,16 +13004,16 @@ OO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.ToggleButtonWidget.super.call( this, config );
+ OO.ui.ToggleButtonWidget.parent.call( this, config );
// Mixin constructors
- 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 } ) );
+ OO.ui.mixin.ButtonElement.call( this, config );
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.IndicatorElement.call( this, config );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.TitledElement.call( this, $.extend( {}, config, { $titled: this.$button } ) );
+ OO.ui.mixin.FlaggedElement.call( this, config );
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$button } ) );
// Events
this.connect( this, { click: 'onAction' } );
@@ -11755,13 +13028,13 @@ OO.ui.ToggleButtonWidget = function OoUiToggleButtonWidget( config ) {
/* Setup */
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 );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.ButtonElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.TitledElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.FlaggedElement );
+OO.mixinClass( OO.ui.ToggleButtonWidget, OO.ui.mixin.TabIndexedElement );
/* Methods */
@@ -11788,7 +13061,7 @@ OO.ui.ToggleButtonWidget.prototype.setValue = function ( value ) {
}
// Parent method
- OO.ui.ToggleButtonWidget.super.prototype.setValue.call( this, value );
+ OO.ui.ToggleButtonWidget.parent.prototype.setValue.call( this, value );
return this;
};
@@ -11800,15 +13073,702 @@ OO.ui.ToggleButtonWidget.prototype.setButtonElement = function ( $button ) {
if ( this.$button ) {
this.$button.removeAttr( 'aria-pressed' );
}
- OO.ui.ButtonElement.prototype.setButtonElement.call( this, $button );
+ OO.ui.mixin.ButtonElement.prototype.setButtonElement.call( this, $button );
this.$button.attr( 'aria-pressed', this.value.toString() );
};
/**
+ * CapsuleMultiSelectWidgets are something like a {@link OO.ui.ComboBoxWidget combo box widget}
+ * that allows for selecting multiple values.
+ *
+ * For more information about menus and options, please see the [OOjs UI documentation on MediaWiki][1].
+ *
+ * @example
+ * // Example: A CapsuleMultiSelectWidget.
+ * var capsule = new OO.ui.CapsuleMultiSelectWidget( {
+ * label: 'CapsuleMultiSelectWidget',
+ * selected: [ 'Option 1', 'Option 3' ],
+ * 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( capsule.$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.mixin.TabIndexedElement
+ * @mixins OO.ui.mixin.GroupElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {boolean} [allowArbitrary=false] Allow data items to be added even if not present in the menu.
+ * @cfg {Object} [menu] Configuration options to pass to the {@link OO.ui.MenuSelectWidget menu select widget}.
+ * @cfg {Object} [popup] Configuration options to pass to the {@link OO.ui.PopupWidget popup widget}.
+ * If specified, this popup will be shown instead of the menu (but the menu
+ * will still be used for item labels and allowArbitrary=false). The widgets
+ * in the popup should use this.addItemsFromData() or this.addItems() as necessary.
+ * @cfg {jQuery} [$overlay] Render the menu or popup 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.CapsuleMultiSelectWidget = function OoUiCapsuleMultiSelectWidget( config ) {
+ var $tabFocus;
+
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.CapsuleMultiSelectWidget.parent.call( this, config );
+
+ // Properties (must be set before mixin constructor calls)
+ this.$input = config.popup ? null : $( '<input>' );
+ this.$handle = $( '<div>' );
+
+ // Mixin constructors
+ OO.ui.mixin.GroupElement.call( this, config );
+ if ( config.popup ) {
+ config.popup = $.extend( {}, config.popup, {
+ align: 'forwards',
+ anchor: false
+ } );
+ OO.ui.mixin.PopupElement.call( this, config );
+ $tabFocus = $( '<span>' );
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: $tabFocus } ) );
+ } else {
+ this.popup = null;
+ $tabFocus = null;
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$input } ) );
+ }
+ OO.ui.mixin.IndicatorElement.call( this, config );
+ OO.ui.mixin.IconElement.call( this, config );
+
+ // Properties
+ this.allowArbitrary = !!config.allowArbitrary;
+ this.$overlay = config.$overlay || this.$element;
+ this.menu = new OO.ui.FloatingMenuSelectWidget( $.extend(
+ {
+ widget: this,
+ $input: this.$input,
+ $container: this.$element,
+ filterFromInput: true,
+ disabled: this.isDisabled()
+ },
+ config.menu
+ ) );
+
+ // Events
+ if ( this.popup ) {
+ $tabFocus.on( {
+ focus: this.onFocusForPopup.bind( this )
+ } );
+ this.popup.$element.on( 'focusout', this.onPopupFocusOut.bind( this ) );
+ if ( this.popup.$autoCloseIgnore ) {
+ this.popup.$autoCloseIgnore.on( 'focusout', this.onPopupFocusOut.bind( this ) );
+ }
+ this.popup.connect( this, {
+ toggle: function ( visible ) {
+ $tabFocus.toggle( !visible );
+ }
+ } );
+ } else {
+ this.$input.on( {
+ focus: this.onInputFocus.bind( this ),
+ blur: this.onInputBlur.bind( this ),
+ 'propertychange change click mouseup keydown keyup input cut paste select': this.onInputChange.bind( this ),
+ keydown: this.onKeyDown.bind( this ),
+ keypress: this.onKeyPress.bind( this )
+ } );
+ }
+ this.menu.connect( this, {
+ choose: 'onMenuChoose',
+ add: 'onMenuItemsChange',
+ remove: 'onMenuItemsChange'
+ } );
+ this.$handle.on( {
+ click: this.onClick.bind( this )
+ } );
+
+ // Initialization
+ if ( this.$input ) {
+ this.$input.prop( 'disabled', this.isDisabled() );
+ this.$input.attr( {
+ role: 'combobox',
+ 'aria-autocomplete': 'list'
+ } );
+ this.$input.width( '1em' );
+ }
+ if ( config.data ) {
+ this.setItemsFromData( config.data );
+ }
+ this.$group.addClass( 'oo-ui-capsuleMultiSelectWidget-group' );
+ this.$handle.addClass( 'oo-ui-capsuleMultiSelectWidget-handle' )
+ .append( this.$indicator, this.$icon, this.$group );
+ this.$element.addClass( 'oo-ui-capsuleMultiSelectWidget' )
+ .append( this.$handle );
+ if ( this.popup ) {
+ this.$handle.append( $tabFocus );
+ this.$overlay.append( this.popup.$element );
+ } else {
+ this.$handle.append( this.$input );
+ this.$overlay.append( this.menu.$element );
+ }
+ this.onMenuItemsChange();
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.mixin.GroupElement );
+OO.mixinClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.mixin.PopupElement );
+OO.mixinClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.mixin.TabIndexedElement );
+OO.mixinClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.CapsuleMultiSelectWidget, OO.ui.mixin.IconElement );
+
+/* Events */
+
+/**
+ * @event change
+ *
+ * A change event is emitted when the set of selected items changes.
+ *
+ * @param {Mixed[]} datas Data of the now-selected items
+ */
+
+/* Methods */
+
+/**
+ * Construct a OO.ui.CapsuleItemWidget (or a subclass thereof) from given label and data.
+ *
+ * @protected
+ * @param {Mixed} data Custom data of any type.
+ * @param {string} label The label text.
+ * @return {OO.ui.CapsuleItemWidget}
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.createItemWidget = function ( data, label ) {
+ return new OO.ui.CapsuleItemWidget( { data: data, label: label } );
+};
+
+/**
+ * Get the data of the items in the capsule
+ * @return {Mixed[]}
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.getItemsData = function () {
+ return $.map( this.getItems(), function ( e ) { return e.data; } );
+};
+
+/**
+ * Set the items in the capsule by providing data
+ * @chainable
+ * @param {Mixed[]} datas
+ * @return {OO.ui.CapsuleMultiSelectWidget}
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.setItemsFromData = function ( datas ) {
+ var widget = this,
+ menu = this.menu,
+ items = this.getItems();
+
+ $.each( datas, function ( i, data ) {
+ var j, label,
+ item = menu.getItemFromData( data );
+
+ if ( item ) {
+ label = item.label;
+ } else if ( widget.allowArbitrary ) {
+ label = String( data );
+ } else {
+ return;
+ }
+
+ item = null;
+ for ( j = 0; j < items.length; j++ ) {
+ if ( items[ j ].data === data && items[ j ].label === label ) {
+ item = items[ j ];
+ items.splice( j, 1 );
+ break;
+ }
+ }
+ if ( !item ) {
+ item = widget.createItemWidget( data, label );
+ }
+ widget.addItems( [ item ], i );
+ } );
+
+ if ( items.length ) {
+ widget.removeItems( items );
+ }
+
+ return this;
+};
+
+/**
+ * Add items to the capsule by providing their data
+ * @chainable
+ * @param {Mixed[]} datas
+ * @return {OO.ui.CapsuleMultiSelectWidget}
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.addItemsFromData = function ( datas ) {
+ var widget = this,
+ menu = this.menu,
+ items = [];
+
+ $.each( datas, function ( i, data ) {
+ var item;
+
+ if ( !widget.getItemFromData( data ) ) {
+ item = menu.getItemFromData( data );
+ if ( item ) {
+ items.push( widget.createItemWidget( data, item.label ) );
+ } else if ( widget.allowArbitrary ) {
+ items.push( widget.createItemWidget( data, String( data ) ) );
+ }
+ }
+ } );
+
+ if ( items.length ) {
+ this.addItems( items );
+ }
+
+ return this;
+};
+
+/**
+ * Remove items by data
+ * @chainable
+ * @param {Mixed[]} datas
+ * @return {OO.ui.CapsuleMultiSelectWidget}
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.removeItemsFromData = function ( datas ) {
+ var widget = this,
+ items = [];
+
+ $.each( datas, function ( i, data ) {
+ var item = widget.getItemFromData( data );
+ if ( item ) {
+ items.push( item );
+ }
+ } );
+
+ if ( items.length ) {
+ this.removeItems( items );
+ }
+
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.addItems = function ( items ) {
+ var same, i, l,
+ oldItems = this.items.slice();
+
+ OO.ui.mixin.GroupElement.prototype.addItems.call( this, items );
+
+ if ( this.items.length !== oldItems.length ) {
+ same = false;
+ } else {
+ same = true;
+ for ( i = 0, l = oldItems.length; same && i < l; i++ ) {
+ same = same && this.items[ i ] === oldItems[ i ];
+ }
+ }
+ if ( !same ) {
+ this.emit( 'change', this.getItemsData() );
+ }
+
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.removeItems = function ( items ) {
+ var same, i, l,
+ oldItems = this.items.slice();
+
+ OO.ui.mixin.GroupElement.prototype.removeItems.call( this, items );
+
+ if ( this.items.length !== oldItems.length ) {
+ same = false;
+ } else {
+ same = true;
+ for ( i = 0, l = oldItems.length; same && i < l; i++ ) {
+ same = same && this.items[ i ] === oldItems[ i ];
+ }
+ }
+ if ( !same ) {
+ this.emit( 'change', this.getItemsData() );
+ }
+
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.clearItems = function () {
+ if ( this.items.length ) {
+ OO.ui.mixin.GroupElement.prototype.clearItems.call( this );
+ this.emit( 'change', this.getItemsData() );
+ }
+ return this;
+};
+
+/**
+ * Get the capsule widget's menu.
+ * @return {OO.ui.MenuSelectWidget} Menu widget
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.getMenu = function () {
+ return this.menu;
+};
+
+/**
+ * Handle focus events
+ *
+ * @private
+ * @param {jQuery.Event} event
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.onInputFocus = function () {
+ if ( !this.isDisabled() ) {
+ this.menu.toggle( true );
+ }
+};
+
+/**
+ * Handle blur events
+ *
+ * @private
+ * @param {jQuery.Event} event
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.onInputBlur = function () {
+ if ( this.allowArbitrary && this.$input.val().trim() !== '' ) {
+ this.addItemsFromData( [ this.$input.val() ] );
+ }
+ this.clearInput();
+};
+
+/**
+ * Handle focus events
+ *
+ * @private
+ * @param {jQuery.Event} event
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.onFocusForPopup = function () {
+ if ( !this.isDisabled() ) {
+ this.popup.setSize( this.$handle.width() );
+ this.popup.toggle( true );
+ this.popup.$element.find( '*' )
+ .filter( function () { return OO.ui.isFocusableElement( $( this ), true ); } )
+ .first()
+ .focus();
+ }
+};
+
+/**
+ * Handles popup focus out events.
+ *
+ * @private
+ * @param {Event} e Focus out event
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.onPopupFocusOut = function () {
+ var widget = this.popup;
+
+ setTimeout( function () {
+ if (
+ widget.isVisible() &&
+ !OO.ui.contains( widget.$element[ 0 ], document.activeElement, true ) &&
+ ( !widget.$autoCloseIgnore || !widget.$autoCloseIgnore.has( document.activeElement ).length )
+ ) {
+ widget.toggle( false );
+ }
+ } );
+};
+
+/**
+ * Handle mouse click events.
+ *
+ * @private
+ * @param {jQuery.Event} e Mouse click event
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.onClick = function ( e ) {
+ if ( e.which === 1 ) {
+ this.focus();
+ return false;
+ }
+};
+
+/**
+ * Handle key press events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key press event
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.onKeyPress = function ( e ) {
+ var item;
+
+ if ( !this.isDisabled() ) {
+ if ( e.which === OO.ui.Keys.ESCAPE ) {
+ this.clearInput();
+ return false;
+ }
+
+ if ( !this.popup ) {
+ this.menu.toggle( true );
+ if ( e.which === OO.ui.Keys.ENTER ) {
+ item = this.menu.getItemFromLabel( this.$input.val(), true );
+ if ( item ) {
+ this.addItemsFromData( [ item.data ] );
+ this.clearInput();
+ } else if ( this.allowArbitrary && this.$input.val().trim() !== '' ) {
+ this.addItemsFromData( [ this.$input.val() ] );
+ this.clearInput();
+ }
+ return false;
+ }
+
+ // Make sure the input gets resized.
+ setTimeout( this.onInputChange.bind( this ), 0 );
+ }
+ }
+};
+
+/**
+ * Handle key down events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key down event
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.onKeyDown = function ( e ) {
+ if ( !this.isDisabled() ) {
+ // 'keypress' event is not triggered for Backspace
+ if ( e.keyCode === OO.ui.Keys.BACKSPACE && this.$input.val() === '' ) {
+ if ( this.items.length ) {
+ this.removeItems( this.items.slice( -1 ) );
+ }
+ return false;
+ }
+ }
+};
+
+/**
+ * Handle input change events.
+ *
+ * @private
+ * @param {jQuery.Event} e Event of some sort
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.onInputChange = function () {
+ if ( !this.isDisabled() ) {
+ this.$input.width( this.$input.val().length + 'em' );
+ }
+};
+
+/**
+ * Handle menu choose events.
+ *
+ * @private
+ * @param {OO.ui.OptionWidget} item Chosen item
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.onMenuChoose = function ( item ) {
+ if ( item && item.isVisible() ) {
+ this.addItemsFromData( [ item.getData() ] );
+ this.clearInput();
+ }
+};
+
+/**
+ * Handle menu item change events.
+ *
+ * @private
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.onMenuItemsChange = function () {
+ this.setItemsFromData( this.getItemsData() );
+ this.$element.toggleClass( 'oo-ui-capsuleMultiSelectWidget-empty', this.menu.isEmpty() );
+};
+
+/**
+ * Clear the input field
+ * @private
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.clearInput = function () {
+ if ( this.$input ) {
+ this.$input.val( '' );
+ this.$input.width( '1em' );
+ }
+ if ( this.popup ) {
+ this.popup.toggle( false );
+ }
+ this.menu.toggle( false );
+ this.menu.selectItem();
+ this.menu.highlightItem();
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.setDisabled = function ( disabled ) {
+ var i, len;
+
+ // Parent method
+ OO.ui.CapsuleMultiSelectWidget.parent.prototype.setDisabled.call( this, disabled );
+
+ if ( this.$input ) {
+ this.$input.prop( 'disabled', this.isDisabled() );
+ }
+ if ( this.menu ) {
+ this.menu.setDisabled( this.isDisabled() );
+ }
+ if ( this.popup ) {
+ this.popup.setDisabled( this.isDisabled() );
+ }
+
+ if ( this.items ) {
+ for ( i = 0, len = this.items.length; i < len; i++ ) {
+ this.items[ i ].updateDisabled();
+ }
+ }
+
+ return this;
+};
+
+/**
+ * Focus the widget
+ * @chainable
+ * @return {OO.ui.CapsuleMultiSelectWidget}
+ */
+OO.ui.CapsuleMultiSelectWidget.prototype.focus = function () {
+ if ( !this.isDisabled() ) {
+ if ( this.popup ) {
+ this.popup.setSize( this.$handle.width() );
+ this.popup.toggle( true );
+ this.popup.$element.find( '*' )
+ .filter( function () { return OO.ui.isFocusableElement( $( this ), true ); } )
+ .first()
+ .focus();
+ } else {
+ this.menu.toggle( true );
+ this.$input.focus();
+ }
+ }
+ return this;
+};
+
+/**
+ * CapsuleItemWidgets are used within a {@link OO.ui.CapsuleMultiSelectWidget
+ * CapsuleMultiSelectWidget} to display the selected items.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.ItemWidget
+ * @mixins OO.ui.mixin.IndicatorElement
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.FlaggedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+OO.ui.CapsuleItemWidget = function OoUiCapsuleItemWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Parent constructor
+ OO.ui.CapsuleItemWidget.parent.call( this, config );
+
+ // Properties (must be set before mixin constructor calls)
+ this.$indicator = $( '<span>' );
+
+ // Mixin constructors
+ OO.ui.mixin.ItemWidget.call( this );
+ OO.ui.mixin.IndicatorElement.call( this, $.extend( {}, config, { $indicator: this.$indicator, indicator: 'clear' } ) );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.FlaggedElement.call( this, config );
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$indicator } ) );
+
+ // Events
+ this.$indicator.on( {
+ keydown: this.onCloseKeyDown.bind( this ),
+ click: this.onCloseClick.bind( this )
+ } );
+
+ // Initialization
+ this.$element
+ .addClass( 'oo-ui-capsuleItemWidget' )
+ .append( this.$indicator, this.$label );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.CapsuleItemWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.CapsuleItemWidget, OO.ui.mixin.ItemWidget );
+OO.mixinClass( OO.ui.CapsuleItemWidget, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.CapsuleItemWidget, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.CapsuleItemWidget, OO.ui.mixin.FlaggedElement );
+OO.mixinClass( OO.ui.CapsuleItemWidget, OO.ui.mixin.TabIndexedElement );
+
+/* Methods */
+
+/**
+ * Handle close icon clicks
+ * @param {jQuery.Event} event
+ */
+OO.ui.CapsuleItemWidget.prototype.onCloseClick = function () {
+ var element = this.getElementGroup();
+
+ if ( !this.isDisabled() && element && $.isFunction( element.removeItems ) ) {
+ element.removeItems( [ this ] );
+ element.focus();
+ }
+};
+
+/**
+ * Handle close keyboard events
+ * @param {jQuery.Event} event Key down event
+ */
+OO.ui.CapsuleItemWidget.prototype.onCloseKeyDown = function ( e ) {
+ if ( !this.isDisabled() && $.isFunction( this.getElementGroup().removeItems ) ) {
+ switch ( e.which ) {
+ case OO.ui.Keys.ENTER:
+ case OO.ui.Keys.BACKSPACE:
+ case OO.ui.Keys.SPACE:
+ this.getElementGroup().removeItems( [ this ] );
+ return false;
+ }
+ }
+};
+
+/**
* 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.
*
+ * If you want to use this within a HTML form, such as a OO.ui.FormLayout, use
+ * OO.ui.DropdownInputWidget instead.
+ *
* @example
* // Example: A DropdownWidget with a menu that contains three options
* var dropDown = new OO.ui.DropdownWidget( {
@@ -11833,41 +13793,52 @@ OO.ui.ToggleButtonWidget.prototype.setButtonElement = function ( $button ) {
*
* $( 'body' ).append( dropDown.$element );
*
+ * dropDown.getMenu().selectItemByData( 'b' );
+ *
+ * dropDown.getMenu().getSelectedItem().getData(); // returns 'b'
+ *
* For more information, please see the [OOjs UI documentation on MediaWiki] [1].
*
* [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
*
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.TitledElement
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.IndicatorElement
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.TitledElement
+ * @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {Object} [menu] Configuration options to pass to menu widget
+ * @cfg {Object} [menu] Configuration options to pass to {@link OO.ui.FloatingMenuSelectWidget menu select 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.DropdownWidget = function OoUiDropdownWidget( config ) {
// Configuration initialization
config = $.extend( { indicator: 'down' }, config );
// Parent constructor
- OO.ui.DropdownWidget.super.call( this, config );
+ OO.ui.DropdownWidget.parent.call( this, config );
// Properties (must be set before TabIndexedElement constructor call)
this.$handle = this.$( '<span>' );
+ this.$overlay = config.$overlay || this.$element;
// 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 } ) );
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.IndicatorElement.call( this, config );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.TitledElement.call( this, $.extend( {}, config, { $titled: this.$label } ) );
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$handle } ) );
// Properties
- this.menu = new OO.ui.MenuSelectWidget( $.extend( { widget: this }, config.menu ) );
+ this.menu = new OO.ui.FloatingMenuSelectWidget( $.extend( {
+ widget: this,
+ $container: this.$element
+ }, config.menu ) );
// Events
this.$handle.on( {
@@ -11882,17 +13853,18 @@ OO.ui.DropdownWidget = function OoUiDropdownWidget( config ) {
.append( this.$icon, this.$label, this.$indicator );
this.$element
.addClass( 'oo-ui-dropdownWidget' )
- .append( this.$handle, this.menu.$element );
+ .append( this.$handle );
+ this.$overlay.append( this.menu.$element );
};
/* Setup */
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 );
+OO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.TitledElement );
+OO.mixinClass( OO.ui.DropdownWidget, OO.ui.mixin.TabIndexedElement );
/* Methods */
@@ -11915,6 +13887,7 @@ OO.ui.DropdownWidget.prototype.onMenuSelect = function ( item ) {
var selectedLabel;
if ( !item ) {
+ this.setLabel( null );
return;
}
@@ -11948,14 +13921,450 @@ OO.ui.DropdownWidget.prototype.onClick = function ( e ) {
* @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 ) ) {
+ if ( !this.isDisabled() &&
+ ( ( e.which === OO.ui.Keys.SPACE && !this.menu.isVisible() ) || e.which === OO.ui.Keys.ENTER )
+ ) {
this.menu.toggle();
return false;
}
};
/**
- * IconWidget is a generic widget for {@link OO.ui.IconElement icons}. In general, IconWidgets should be used with OO.ui.LabelWidget,
+ * SelectFileWidgets allow for selecting files, using the HTML5 File API. These
+ * widgets can be configured with {@link OO.ui.mixin.IconElement icons} and {@link
+ * OO.ui.mixin.IndicatorElement indicators}.
+ * Please see the [OOjs UI documentation on MediaWiki] [1] for more information and examples.
+ *
+ * @example
+ * // Example of a file select widget
+ * var selectFile = new OO.ui.SelectFileWidget();
+ * $( 'body' ).append( selectFile.$element );
+ *
+ * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.IndicatorElement
+ * @mixins OO.ui.mixin.PendingElement
+ * @mixins OO.ui.mixin.LabelElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string[]|null} [accept=null] MIME types to accept. null accepts all types.
+ * @cfg {string} [placeholder] Text to display when no file is selected.
+ * @cfg {string} [notsupported] Text to display when file support is missing in the browser.
+ * @cfg {boolean} [droppable=true] Whether to accept files by drag and drop.
+ * @cfg {boolean} [showDropTarget=false] Whether to show a drop target. Requires droppable to be true.
+ * @cfg {boolean} [dragDropUI=false] Deprecated alias for showDropTarget
+ */
+OO.ui.SelectFileWidget = function OoUiSelectFileWidget( config ) {
+ var dragHandler;
+
+ // TODO: Remove in next release
+ if ( config && config.dragDropUI ) {
+ config.showDropTarget = true;
+ }
+
+ // Configuration initialization
+ config = $.extend( {
+ accept: null,
+ placeholder: OO.ui.msg( 'ooui-selectfile-placeholder' ),
+ notsupported: OO.ui.msg( 'ooui-selectfile-not-supported' ),
+ droppable: true,
+ showDropTarget: false
+ }, config );
+
+ // Parent constructor
+ OO.ui.SelectFileWidget.parent.call( this, config );
+
+ // Mixin constructors
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.IndicatorElement.call( this, config );
+ OO.ui.mixin.PendingElement.call( this, $.extend( {}, config, { $pending: this.$info } ) );
+ OO.ui.mixin.LabelElement.call( this, $.extend( {}, config, { autoFitLabel: true } ) );
+
+ // Properties
+ this.$info = $( '<span>' );
+
+ // Properties
+ this.showDropTarget = config.showDropTarget;
+ this.isSupported = this.constructor.static.isSupported();
+ this.currentFile = null;
+ if ( Array.isArray( config.accept ) ) {
+ this.accept = config.accept;
+ } else {
+ this.accept = null;
+ }
+ this.placeholder = config.placeholder;
+ this.notsupported = config.notsupported;
+ this.onFileSelectedHandler = this.onFileSelected.bind( this );
+
+ this.selectButton = new OO.ui.ButtonWidget( {
+ classes: [ 'oo-ui-selectFileWidget-selectButton' ],
+ label: 'Select a file',
+ disabled: this.disabled || !this.isSupported
+ } );
+
+ this.clearButton = new OO.ui.ButtonWidget( {
+ classes: [ 'oo-ui-selectFileWidget-clearButton' ],
+ framed: false,
+ icon: 'remove',
+ disabled: this.disabled
+ } );
+
+ // Events
+ this.selectButton.$button.on( {
+ keypress: this.onKeyPress.bind( this )
+ } );
+ this.clearButton.connect( this, {
+ click: 'onClearClick'
+ } );
+ if ( config.droppable ) {
+ dragHandler = this.onDragEnterOrOver.bind( this );
+ this.$element.on( {
+ dragenter: dragHandler,
+ dragover: dragHandler,
+ dragleave: this.onDragLeave.bind( this ),
+ drop: this.onDrop.bind( this )
+ } );
+ }
+
+ // Initialization
+ this.addInput();
+ this.updateUI();
+ this.$label.addClass( 'oo-ui-selectFileWidget-label' );
+ this.$info
+ .addClass( 'oo-ui-selectFileWidget-info' )
+ .append( this.$icon, this.$label, this.clearButton.$element, this.$indicator );
+ this.$element
+ .addClass( 'oo-ui-selectFileWidget' )
+ .append( this.$info, this.selectButton.$element );
+ if ( config.droppable && config.showDropTarget ) {
+ this.$dropTarget = $( '<div>' )
+ .addClass( 'oo-ui-selectFileWidget-dropTarget' )
+ .text( OO.ui.msg( 'ooui-selectfile-dragdrop-placeholder' ) )
+ .on( {
+ click: this.onDropTargetClick.bind( this )
+ } );
+ this.$element.prepend( this.$dropTarget );
+ }
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.SelectFileWidget, OO.ui.Widget );
+OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.PendingElement );
+OO.mixinClass( OO.ui.SelectFileWidget, OO.ui.mixin.LabelElement );
+
+/* Static Properties */
+
+/**
+ * Check if this widget is supported
+ *
+ * @static
+ * @return {boolean}
+ */
+OO.ui.SelectFileWidget.static.isSupported = function () {
+ var $input;
+ if ( OO.ui.SelectFileWidget.static.isSupportedCache === null ) {
+ $input = $( '<input type="file">' );
+ OO.ui.SelectFileWidget.static.isSupportedCache = $input[ 0 ].files !== undefined;
+ }
+ return OO.ui.SelectFileWidget.static.isSupportedCache;
+};
+
+OO.ui.SelectFileWidget.static.isSupportedCache = null;
+
+/* Events */
+
+/**
+ * @event change
+ *
+ * A change event is emitted when the on/off state of the toggle changes.
+ *
+ * @param {File|null} value New value
+ */
+
+/* Methods */
+
+/**
+ * Get the current value of the field
+ *
+ * @return {File|null}
+ */
+OO.ui.SelectFileWidget.prototype.getValue = function () {
+ return this.currentFile;
+};
+
+/**
+ * Set the current value of the field
+ *
+ * @param {File|null} file File to select
+ */
+OO.ui.SelectFileWidget.prototype.setValue = function ( file ) {
+ if ( this.currentFile !== file ) {
+ this.currentFile = file;
+ this.updateUI();
+ this.emit( 'change', this.currentFile );
+ }
+};
+
+/**
+ * Focus the widget.
+ *
+ * Focusses the select file button.
+ *
+ * @chainable
+ */
+OO.ui.SelectFileWidget.prototype.focus = function () {
+ this.selectButton.$button[ 0 ].focus();
+ return this;
+};
+
+/**
+ * Update the user interface when a file is selected or unselected
+ *
+ * @protected
+ */
+OO.ui.SelectFileWidget.prototype.updateUI = function () {
+ var $label;
+ if ( !this.isSupported ) {
+ this.$element.addClass( 'oo-ui-selectFileWidget-notsupported' );
+ this.$element.removeClass( 'oo-ui-selectFileWidget-empty' );
+ this.setLabel( this.notsupported );
+ } else {
+ this.$element.addClass( 'oo-ui-selectFileWidget-supported' );
+ if ( this.currentFile ) {
+ this.$element.removeClass( 'oo-ui-selectFileWidget-empty' );
+ $label = $( [] );
+ if ( this.currentFile.type !== '' ) {
+ $label = $label.add( $( '<span>' ).addClass( 'oo-ui-selectFileWidget-fileType' ).text( this.currentFile.type ) );
+ }
+ $label = $label.add( $( '<span>' ).text( this.currentFile.name ) );
+ this.setLabel( $label );
+ } else {
+ this.$element.addClass( 'oo-ui-selectFileWidget-empty' );
+ this.setLabel( this.placeholder );
+ }
+ }
+
+ if ( this.$input ) {
+ this.$input.attr( 'title', this.getLabel() );
+ }
+};
+
+/**
+ * Add the input to the widget
+ *
+ * @private
+ */
+OO.ui.SelectFileWidget.prototype.addInput = function () {
+ if ( this.$input ) {
+ this.$input.remove();
+ }
+
+ if ( !this.isSupported ) {
+ this.$input = null;
+ return;
+ }
+
+ this.$input = $( '<input type="file">' );
+ this.$input.on( 'change', this.onFileSelectedHandler );
+ this.$input.attr( {
+ tabindex: -1,
+ title: this.getLabel()
+ } );
+ if ( this.accept ) {
+ this.$input.attr( 'accept', this.accept.join( ', ' ) );
+ }
+ this.selectButton.$button.append( this.$input );
+};
+
+/**
+ * Determine if we should accept this file
+ *
+ * @private
+ * @param {string} File MIME type
+ * @return {boolean}
+ */
+OO.ui.SelectFileWidget.prototype.isAllowedType = function ( mimeType ) {
+ var i, mimeTest;
+
+ if ( !this.accept || !mimeType ) {
+ return true;
+ }
+
+ for ( i = 0; i < this.accept.length; i++ ) {
+ mimeTest = this.accept[ i ];
+ if ( mimeTest === mimeType ) {
+ return true;
+ } else if ( mimeTest.substr( -2 ) === '/*' ) {
+ mimeTest = mimeTest.substr( 0, mimeTest.length - 1 );
+ if ( mimeType.substr( 0, mimeTest.length ) === mimeTest ) {
+ return true;
+ }
+ }
+ }
+
+ return false;
+};
+
+/**
+ * Handle file selection from the input
+ *
+ * @private
+ * @param {jQuery.Event} e
+ */
+OO.ui.SelectFileWidget.prototype.onFileSelected = function ( e ) {
+ var file = OO.getProp( e.target, 'files', 0 ) || null;
+
+ if ( file && !this.isAllowedType( file.type ) ) {
+ file = null;
+ }
+
+ this.setValue( file );
+ this.addInput();
+};
+
+/**
+ * Handle clear button click events.
+ *
+ * @private
+ */
+OO.ui.SelectFileWidget.prototype.onClearClick = function () {
+ this.setValue( null );
+ return false;
+};
+
+/**
+ * Handle key press events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key press event
+ */
+OO.ui.SelectFileWidget.prototype.onKeyPress = function ( e ) {
+ if ( this.isSupported && !this.isDisabled() && this.$input &&
+ ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
+ ) {
+ this.$input.click();
+ return false;
+ }
+};
+
+/**
+ * Handle drop target click events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key press event
+ */
+OO.ui.SelectFileWidget.prototype.onDropTargetClick = function () {
+ if ( this.isSupported && !this.isDisabled() && this.$input ) {
+ this.$input.click();
+ return false;
+ }
+};
+
+/**
+ * Handle drag enter and over events
+ *
+ * @private
+ * @param {jQuery.Event} e Drag event
+ */
+OO.ui.SelectFileWidget.prototype.onDragEnterOrOver = function ( e ) {
+ var itemOrFile,
+ droppableFile = false,
+ dt = e.originalEvent.dataTransfer;
+
+ e.preventDefault();
+ e.stopPropagation();
+
+ if ( this.isDisabled() || !this.isSupported ) {
+ this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );
+ dt.dropEffect = 'none';
+ return false;
+ }
+
+ // DataTransferItem and File both have a type property, but in Chrome files
+ // have no information at this point.
+ itemOrFile = OO.getProp( dt, 'items', 0 ) || OO.getProp( dt, 'files', 0 );
+ if ( itemOrFile ) {
+ if ( this.isAllowedType( itemOrFile.type ) ) {
+ droppableFile = true;
+ }
+ // dt.types is Array-like, but not an Array
+ } else if ( Array.prototype.indexOf.call( OO.getProp( dt, 'types' ) || [], 'Files' ) !== -1 ) {
+ // File information is not available at this point for security so just assume
+ // it is acceptable for now.
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=640534
+ droppableFile = true;
+ }
+
+ this.$element.toggleClass( 'oo-ui-selectFileWidget-canDrop', droppableFile );
+ if ( !droppableFile ) {
+ dt.dropEffect = 'none';
+ }
+
+ return false;
+};
+
+/**
+ * Handle drag leave events
+ *
+ * @private
+ * @param {jQuery.Event} e Drag event
+ */
+OO.ui.SelectFileWidget.prototype.onDragLeave = function () {
+ this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );
+};
+
+/**
+ * Handle drop events
+ *
+ * @private
+ * @param {jQuery.Event} e Drop event
+ */
+OO.ui.SelectFileWidget.prototype.onDrop = function ( e ) {
+ var file = null,
+ dt = e.originalEvent.dataTransfer;
+
+ e.preventDefault();
+ e.stopPropagation();
+ this.$element.removeClass( 'oo-ui-selectFileWidget-canDrop' );
+
+ if ( this.isDisabled() || !this.isSupported ) {
+ return false;
+ }
+
+ file = OO.getProp( dt, 'files', 0 );
+ if ( file && !this.isAllowedType( file.type ) ) {
+ file = null;
+ }
+ if ( file ) {
+ this.setValue( file );
+ }
+
+ return false;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.SelectFileWidget.prototype.setDisabled = function ( disabled ) {
+ OO.ui.SelectFileWidget.parent.prototype.setDisabled.call( this, disabled );
+ if ( this.selectButton ) {
+ this.selectButton.setDisabled( disabled );
+ }
+ if ( this.clearButton ) {
+ this.clearButton.setDisabled( disabled );
+ }
+ return this;
+};
+
+/**
+ * IconWidget is a generic widget for {@link OO.ui.mixin.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.
*
@@ -11975,9 +14384,9 @@ OO.ui.DropdownWidget.prototype.onKeyPress = function ( e ) {
*
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.TitledElement
- * @mixins OO.ui.FlaggedElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.TitledElement
+ * @mixins OO.ui.mixin.FlaggedElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -11987,12 +14396,12 @@ OO.ui.IconWidget = function OoUiIconWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.IconWidget.super.call( this, config );
+ OO.ui.IconWidget.parent.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 } ) );
+ OO.ui.mixin.IconElement.call( this, $.extend( {}, config, { $icon: this.$element } ) );
+ OO.ui.mixin.TitledElement.call( this, $.extend( {}, config, { $titled: this.$element } ) );
+ OO.ui.mixin.FlaggedElement.call( this, $.extend( {}, config, { $flagged: this.$element } ) );
// Initialization
this.$element.addClass( 'oo-ui-iconWidget' );
@@ -12001,9 +14410,9 @@ OO.ui.IconWidget = function OoUiIconWidget( config ) {
/* 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 );
+OO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.TitledElement );
+OO.mixinClass( OO.ui.IconWidget, OO.ui.mixin.FlaggedElement );
/* Static Properties */
@@ -12031,8 +14440,8 @@ OO.ui.IconWidget.static.tagName = 'span';
*
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.TitledElement
+ * @mixins OO.ui.mixin.IndicatorElement
+ * @mixins OO.ui.mixin.TitledElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -12042,11 +14451,11 @@ OO.ui.IndicatorWidget = function OoUiIndicatorWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.IndicatorWidget.super.call( this, config );
+ OO.ui.IndicatorWidget.parent.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 } ) );
+ OO.ui.mixin.IndicatorElement.call( this, $.extend( {}, config, { $indicator: this.$element } ) );
+ OO.ui.mixin.TitledElement.call( this, $.extend( {}, config, { $titled: this.$element } ) );
// Initialization
this.$element.addClass( 'oo-ui-indicatorWidget' );
@@ -12055,8 +14464,8 @@ OO.ui.IndicatorWidget = function OoUiIndicatorWidget( config ) {
/* 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 );
+OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.IndicatorWidget, OO.ui.mixin.TitledElement );
/* Static Properties */
@@ -12073,13 +14482,16 @@ OO.ui.IndicatorWidget.static.tagName = 'span';
* @abstract
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.FlaggedElement
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.FlaggedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
+ * @mixins OO.ui.mixin.TitledElement
+ * @mixins OO.ui.mixin.AccessKeyedElement
*
* @constructor
* @param {Object} [config] Configuration options
* @cfg {string} [name=''] The value of the input’s HTML `name` attribute.
* @cfg {string} [value=''] The value of the input.
+ * @cfg {string} [accessKey=''] The access key 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.
*/
@@ -12088,7 +14500,7 @@ OO.ui.InputWidget = function OoUiInputWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.InputWidget.super.call( this, config );
+ OO.ui.InputWidget.parent.call( this, config );
// Properties
this.$input = this.getInputElement( config );
@@ -12096,25 +14508,37 @@ OO.ui.InputWidget = function OoUiInputWidget( config ) {
this.inputFilter = config.inputFilter;
// Mixin constructors
- OO.ui.FlaggedElement.call( this, config );
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$input } ) );
+ OO.ui.mixin.FlaggedElement.call( this, config );
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$input } ) );
+ OO.ui.mixin.TitledElement.call( this, $.extend( {}, config, { $titled: this.$input } ) );
+ OO.ui.mixin.AccessKeyedElement.call( this, $.extend( {}, config, { $accessKeyed: this.$input } ) );
// Events
this.$input.on( 'keydown mouseup cut paste change input select', this.onEdit.bind( this ) );
// Initialization
this.$input
+ .addClass( 'oo-ui-inputWidget-input' )
.attr( 'name', config.name )
.prop( 'disabled', this.isDisabled() );
- this.$element.addClass( 'oo-ui-inputWidget' ).append( this.$input, $( '<span>' ) );
+ this.$element
+ .addClass( 'oo-ui-inputWidget' )
+ .append( this.$input );
this.setValue( config.value );
+ this.setAccessKey( config.accessKey );
};
/* 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 );
+OO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.FlaggedElement );
+OO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.TabIndexedElement );
+OO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.TitledElement );
+OO.mixinClass( OO.ui.InputWidget, OO.ui.mixin.AccessKeyedElement );
+
+/* Static Properties */
+
+OO.ui.InputWidget.static.supportsSimpleLabel = true;
/* Events */
@@ -12134,7 +14558,7 @@ OO.mixinClass( OO.ui.InputWidget, OO.ui.TabIndexedElement );
* 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
+ * @protected
* @param {Object} config Configuration options
* @return {jQuery} Input element
*/
@@ -12205,6 +14629,30 @@ OO.ui.InputWidget.prototype.setValue = function ( value ) {
};
/**
+ * Set the input's access key.
+ * FIXME: This is the same code as in OO.ui.mixin.ButtonElement, maybe find a better place for it?
+ *
+ * @param {string} accessKey Input's access key, use empty string to remove
+ * @chainable
+ */
+OO.ui.InputWidget.prototype.setAccessKey = function ( accessKey ) {
+ accessKey = typeof accessKey === 'string' && accessKey.length ? accessKey : null;
+
+ if ( this.accessKey !== accessKey ) {
+ if ( this.$input ) {
+ if ( accessKey !== null ) {
+ this.$input.attr( 'accesskey', accessKey );
+ } else {
+ this.$input.removeAttr( 'accesskey' );
+ }
+ }
+ this.accessKey = accessKey;
+ }
+
+ return this;
+};
+
+/**
* Clean up incoming value.
*
* Ensures value is a string, and converts undefined and null to empty string.
@@ -12243,7 +14691,7 @@ OO.ui.InputWidget.prototype.simulateLabelClick = function () {
* @inheritdoc
*/
OO.ui.InputWidget.prototype.setDisabled = function ( state ) {
- OO.ui.InputWidget.super.prototype.setDisabled.call( this, state );
+ OO.ui.InputWidget.parent.prototype.setDisabled.call( this, state );
if ( this.$input ) {
this.$input.prop( 'disabled', this.isDisabled() );
}
@@ -12271,6 +14719,32 @@ OO.ui.InputWidget.prototype.blur = function () {
};
/**
+ * @inheritdoc
+ */
+OO.ui.InputWidget.prototype.gatherPreInfuseState = function ( node ) {
+ var
+ state = OO.ui.InputWidget.parent.prototype.gatherPreInfuseState.call( this, node ),
+ $input = state.$input || $( node ).find( '.oo-ui-inputWidget-input' );
+ state.value = $input.val();
+ // Might be better in TabIndexedElement, but it's awkward to do there because mixins are awkward
+ state.focus = $input.is( ':focus' );
+ return state;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.InputWidget.prototype.restorePreInfuseState = function ( state ) {
+ OO.ui.InputWidget.parent.prototype.restorePreInfuseState.call( this, state );
+ if ( state.value !== undefined && state.value !== this.getValue() ) {
+ this.setValue( state.value );
+ }
+ if ( state.focus ) {
+ this.focus();
+ }
+};
+
+/**
* 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
@@ -12290,11 +14764,11 @@ OO.ui.InputWidget.prototype.blur = function () {
*
* @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
+ * @mixins OO.ui.mixin.ButtonElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.IndicatorElement
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.TitledElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -12312,14 +14786,14 @@ OO.ui.ButtonInputWidget = function OoUiButtonInputWidget( config ) {
this.useInputTag = config.useInputTag;
// Parent constructor
- OO.ui.ButtonInputWidget.super.call( this, config );
+ OO.ui.ButtonInputWidget.parent.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 } ) );
+ OO.ui.mixin.ButtonElement.call( this, $.extend( {}, config, { $button: this.$input } ) );
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.IndicatorElement.call( this, config );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.TitledElement.call( this, $.extend( {}, config, { $titled: this.$input } ) );
// Initialization
if ( !config.useInputTag ) {
@@ -12331,21 +14805,31 @@ OO.ui.ButtonInputWidget = function OoUiButtonInputWidget( config ) {
/* 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 );
+OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.ButtonElement );
+OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.ButtonInputWidget, OO.ui.mixin.TitledElement );
+
+/* Static Properties */
+
+/**
+ * Disable generating `<label>` elements for buttons. One would very rarely need additional label
+ * for a button, and it's already a big clickable target, and it causes unexpected rendering.
+ */
+OO.ui.ButtonInputWidget.static.supportsSimpleLabel = false;
/* Methods */
/**
* @inheritdoc
- * @private
+ * @protected
*/
OO.ui.ButtonInputWidget.prototype.getInputElement = function ( config ) {
- var html = '<' + ( config.useInputTag ? 'input' : 'button' ) + ' type="' + config.type + '">';
- return $( html );
+ var type = [ 'button', 'submit', 'reset' ].indexOf( config.type ) !== -1 ?
+ config.type :
+ 'button';
+ return $( '<' + ( config.useInputTag ? 'input' : 'button' ) + ' type="' + type + '">' );
};
/**
@@ -12358,7 +14842,7 @@ OO.ui.ButtonInputWidget.prototype.getInputElement = function ( config ) {
* @chainable
*/
OO.ui.ButtonInputWidget.prototype.setLabel = function ( label ) {
- OO.ui.LabelElement.prototype.setLabel.call( this, label );
+ OO.ui.mixin.LabelElement.prototype.setLabel.call( this, label );
if ( this.useInputTag ) {
if ( typeof label === 'function' ) {
@@ -12387,7 +14871,7 @@ OO.ui.ButtonInputWidget.prototype.setLabel = function ( label ) {
*/
OO.ui.ButtonInputWidget.prototype.setValue = function ( value ) {
if ( !this.useInputTag ) {
- OO.ui.ButtonInputWidget.super.prototype.setValue.call( this, value );
+ OO.ui.ButtonInputWidget.parent.prototype.setValue.call( this, value );
}
return this;
};
@@ -12438,10 +14922,13 @@ OO.ui.CheckboxInputWidget = function OoUiCheckboxInputWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.CheckboxInputWidget.super.call( this, config );
+ OO.ui.CheckboxInputWidget.parent.call( this, config );
// Initialization
- this.$element.addClass( 'oo-ui-checkboxInputWidget' );
+ this.$element
+ .addClass( 'oo-ui-checkboxInputWidget' )
+ // Required for pretty styling in MediaWiki theme
+ .append( $( '<span>' ) );
this.setSelected( config.selected !== undefined ? config.selected : false );
};
@@ -12453,7 +14940,7 @@ OO.inheritClass( OO.ui.CheckboxInputWidget, OO.ui.InputWidget );
/**
* @inheritdoc
- * @private
+ * @protected
*/
OO.ui.CheckboxInputWidget.prototype.getInputElement = function () {
return $( '<input type="checkbox" />' );
@@ -12504,41 +14991,73 @@ OO.ui.CheckboxInputWidget.prototype.isSelected = function () {
};
/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxInputWidget.prototype.gatherPreInfuseState = function ( node ) {
+ var
+ state = OO.ui.CheckboxInputWidget.parent.prototype.gatherPreInfuseState.call( this, node ),
+ $input = $( node ).find( '.oo-ui-inputWidget-input' );
+ state.$input = $input; // shortcut for performance, used in InputWidget
+ state.checked = $input.prop( 'checked' );
+ return state;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.CheckboxInputWidget.prototype.restorePreInfuseState = function ( state ) {
+ OO.ui.CheckboxInputWidget.parent.prototype.restorePreInfuseState.call( this, state );
+ if ( state.checked !== undefined && state.checked !== this.isSelected() ) {
+ this.setSelected( state.checked );
+ }
+};
+
+/**
* 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.
*
+ * A DropdownInputWidget always has a value (one of the options is always selected), unless there
+ * are no options. If no `value` configuration option is provided, the first option is selected.
+ * If you need a state representing no value (no option being selected), use a DropdownWidget.
+ *
+ * This and OO.ui.RadioSelectInputWidget support the same configuration options.
+ *
* @example
* // Example: A DropdownInputWidget with three options
- * var dropDown = new OO.ui.DropdownInputWidget( {
- * label: 'Dropdown menu: Select a menu option',
+ * var dropdownInput = new OO.ui.DropdownInputWidget( {
* options: [
- * { data: 'a', label: 'First' } ,
- * { data: 'b', label: 'Second'} ,
+ * { data: 'a', label: 'First' },
+ * { data: 'b', label: 'Second'},
* { data: 'c', label: 'Third' }
* ]
* } );
- * $( 'body' ).append( dropDown.$element );
+ * $( 'body' ).append( dropdownInput.$element );
*
* [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Inputs
*
* @class
* @extends OO.ui.InputWidget
+ * @mixins OO.ui.mixin.TitledElement
*
* @constructor
* @param {Object} [config] Configuration options
* @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`
+ * @cfg {Object} [dropdown] Configuration options for {@link OO.ui.DropdownWidget DropdownWidget}
*/
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();
+ this.dropdownWidget = new OO.ui.DropdownWidget( config.dropdown );
// Parent constructor
- OO.ui.DropdownInputWidget.super.call( this, config );
+ OO.ui.DropdownInputWidget.parent.call( this, config );
+
+ // Mixin constructors
+ OO.ui.mixin.TitledElement.call( this, config );
// Events
this.dropdownWidget.getMenu().connect( this, { select: 'onMenuSelect' } );
@@ -12553,12 +15072,13 @@ OO.ui.DropdownInputWidget = function OoUiDropdownInputWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.DropdownInputWidget, OO.ui.InputWidget );
+OO.mixinClass( OO.ui.DropdownInputWidget, OO.ui.mixin.TitledElement );
/* Methods */
/**
* @inheritdoc
- * @private
+ * @protected
*/
OO.ui.DropdownInputWidget.prototype.getInputElement = function () {
return $( '<input type="hidden">' );
@@ -12578,8 +15098,9 @@ OO.ui.DropdownInputWidget.prototype.onMenuSelect = function ( item ) {
* @inheritdoc
*/
OO.ui.DropdownInputWidget.prototype.setValue = function ( value ) {
+ value = this.cleanUpValue( value );
this.dropdownWidget.getMenu().selectItemByData( value );
- OO.ui.DropdownInputWidget.super.prototype.setValue.call( this, value );
+ OO.ui.DropdownInputWidget.parent.prototype.setValue.call( this, value );
return this;
};
@@ -12588,7 +15109,7 @@ OO.ui.DropdownInputWidget.prototype.setValue = function ( value ) {
*/
OO.ui.DropdownInputWidget.prototype.setDisabled = function ( state ) {
this.dropdownWidget.setDisabled( state );
- OO.ui.DropdownInputWidget.super.prototype.setDisabled.call( this, state );
+ OO.ui.DropdownInputWidget.parent.prototype.setDisabled.call( this, state );
return this;
};
@@ -12599,15 +15120,18 @@ OO.ui.DropdownInputWidget.prototype.setDisabled = function ( state ) {
* @chainable
*/
OO.ui.DropdownInputWidget.prototype.setOptions = function ( options ) {
- var value = this.getValue();
+ var
+ value = this.getValue(),
+ widget = this;
// Rebuild the dropdown menu
this.dropdownWidget.getMenu()
.clearItems()
.addItems( options.map( function ( opt ) {
+ var optValue = widget.cleanUpValue( opt.data );
return new OO.ui.MenuOptionWidget( {
- data: opt.data,
- label: opt.label !== undefined ? opt.label : opt.data
+ data: optValue,
+ label: opt.label !== undefined ? opt.label : optValue
} );
} ) );
@@ -12687,10 +15211,13 @@ OO.ui.RadioInputWidget = function OoUiRadioInputWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.RadioInputWidget.super.call( this, config );
+ OO.ui.RadioInputWidget.parent.call( this, config );
// Initialization
- this.$element.addClass( 'oo-ui-radioInputWidget' );
+ this.$element
+ .addClass( 'oo-ui-radioInputWidget' )
+ // Required for pretty styling in MediaWiki theme
+ .append( $( '<span>' ) );
this.setSelected( config.selected !== undefined ? config.selected : false );
};
@@ -12702,7 +15229,7 @@ OO.inheritClass( OO.ui.RadioInputWidget, OO.ui.InputWidget );
/**
* @inheritdoc
- * @private
+ * @protected
*/
OO.ui.RadioInputWidget.prototype.getInputElement = function () {
return $( '<input type="radio" />' );
@@ -12737,9 +15264,171 @@ OO.ui.RadioInputWidget.prototype.isSelected = function () {
};
/**
+ * @inheritdoc
+ */
+OO.ui.RadioInputWidget.prototype.gatherPreInfuseState = function ( node ) {
+ var
+ state = OO.ui.RadioInputWidget.parent.prototype.gatherPreInfuseState.call( this, node ),
+ $input = $( node ).find( '.oo-ui-inputWidget-input' );
+ state.$input = $input; // shortcut for performance, used in InputWidget
+ state.checked = $input.prop( 'checked' );
+ return state;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.RadioInputWidget.prototype.restorePreInfuseState = function ( state ) {
+ OO.ui.RadioInputWidget.parent.prototype.restorePreInfuseState.call( this, state );
+ if ( state.checked !== undefined && state.checked !== this.isSelected() ) {
+ this.setSelected( state.checked );
+ }
+};
+
+/**
+ * RadioSelectInputWidget is a {@link OO.ui.RadioSelectWidget RadioSelectWidget} 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.
+ *
+ * This and OO.ui.DropdownInputWidget support the same configuration options.
+ *
+ * @example
+ * // Example: A RadioSelectInputWidget with three options
+ * var radioSelectInput = new OO.ui.RadioSelectInputWidget( {
+ * options: [
+ * { data: 'a', label: 'First' },
+ * { data: 'b', label: 'Second'},
+ * { data: 'c', label: 'Third' }
+ * ]
+ * } );
+ * $( 'body' ).append( radioSelectInput.$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.RadioSelectInputWidget = function OoUiRadioSelectInputWidget( config ) {
+ // Configuration initialization
+ config = config || {};
+
+ // Properties (must be done before parent constructor which calls #setDisabled)
+ this.radioSelectWidget = new OO.ui.RadioSelectWidget();
+
+ // Parent constructor
+ OO.ui.RadioSelectInputWidget.parent.call( this, config );
+
+ // Events
+ this.radioSelectWidget.connect( this, { select: 'onMenuSelect' } );
+
+ // Initialization
+ this.setOptions( config.options || [] );
+ this.$element
+ .addClass( 'oo-ui-radioSelectInputWidget' )
+ .append( this.radioSelectWidget.$element );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.RadioSelectInputWidget, OO.ui.InputWidget );
+
+/* Static Properties */
+
+OO.ui.RadioSelectInputWidget.static.supportsSimpleLabel = false;
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ * @protected
+ */
+OO.ui.RadioSelectInputWidget.prototype.getInputElement = function () {
+ return $( '<input type="hidden">' );
+};
+
+/**
+ * Handles menu select events.
+ *
+ * @private
+ * @param {OO.ui.RadioOptionWidget} item Selected menu item
+ */
+OO.ui.RadioSelectInputWidget.prototype.onMenuSelect = function ( item ) {
+ this.setValue( item.getData() );
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.RadioSelectInputWidget.prototype.setValue = function ( value ) {
+ value = this.cleanUpValue( value );
+ this.radioSelectWidget.selectItemByData( value );
+ OO.ui.RadioSelectInputWidget.parent.prototype.setValue.call( this, value );
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.RadioSelectInputWidget.prototype.setDisabled = function ( state ) {
+ this.radioSelectWidget.setDisabled( state );
+ OO.ui.RadioSelectInputWidget.parent.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.RadioSelectInputWidget.prototype.setOptions = function ( options ) {
+ var
+ value = this.getValue(),
+ widget = this;
+
+ // Rebuild the radioSelect menu
+ this.radioSelectWidget
+ .clearItems()
+ .addItems( options.map( function ( opt ) {
+ var optValue = widget.cleanUpValue( opt.data );
+ return new OO.ui.RadioOptionWidget( {
+ data: optValue,
+ label: opt.label !== undefined ? opt.label : optValue
+ } );
+ } ) );
+
+ // Restore the previous value, or reset to something sensible
+ if ( this.radioSelectWidget.getItemFromData( value ) ) {
+ // Previous value is still available, ensure consistency with the radioSelect
+ this.setValue( value );
+ } else {
+ // No longer valid, reset
+ if ( options.length ) {
+ this.setValue( options[ 0 ].data );
+ }
+ }
+
+ return this;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.RadioSelectInputWidget.prototype.gatherPreInfuseState = function ( node ) {
+ var state = OO.ui.RadioSelectInputWidget.parent.prototype.gatherPreInfuseState.call( this, node );
+ state.value = $( node ).find( '.oo-ui-radioInputWidget .oo-ui-inputWidget-input:checked' ).val();
+ return state;
+};
+
+/**
* 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
+ * with {@link OO.ui.mixin.IconElement icons}, {@link OO.ui.mixin.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.
@@ -12757,26 +15446,36 @@ OO.ui.RadioInputWidget.prototype.isSelected = function () {
*
* @class
* @extends OO.ui.InputWidget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
- * @mixins OO.ui.PendingElement
- * @mixins OO.ui.LabelElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.IndicatorElement
+ * @mixins OO.ui.mixin.PendingElement
+ * @mixins OO.ui.mixin.LabelElement
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {string} [type='text'] The value of the HTML `type` attribute
+ * @cfg {string} [type='text'] The value of the HTML `type` attribute: 'text', 'password', 'search',
+ * 'email' or 'url'. Ignored if `multiline` is true.
+ *
+ * Some values of `type` result in additional behaviors:
+ *
+ * - `search`: implies `icon: 'search'` and `indicator: 'clear'`; when clicked, the indicator
+ * empties the text field
* @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 {number} [rows] If multiline, number of visible lines in textarea. If used with `autosize`,
+ * specifies minimum number of rows to display.
* @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 {boolean} [maxRows] Maximum number of rows to display when #autosize is set to true.
+ * Defaults to the maximum of `10` and `2 * rows`, or `10` if `rows` isn't provided.
* @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 {boolean} [required=false] Mark the field as required. Implies `indicator: 'required'`.
+ * @cfg {boolean} [autocomplete=true] Should the browser support autocomplete for this field
* @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
@@ -12787,24 +15486,36 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
// Configuration initialization
config = $.extend( {
type: 'text',
- labelPosition: 'after',
- maxRows: 10
+ labelPosition: 'after'
}, config );
+ if ( config.type === 'search' ) {
+ if ( config.icon === undefined ) {
+ config.icon = 'search';
+ }
+ // indicator: 'clear' is set dynamically later, depending on value
+ }
+ if ( config.required ) {
+ if ( config.indicator === undefined ) {
+ config.indicator = 'required';
+ }
+ }
// Parent constructor
- OO.ui.TextInputWidget.super.call( this, config );
+ OO.ui.TextInputWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.IconElement.call( this, config );
- OO.ui.IndicatorElement.call( this, config );
- OO.ui.PendingElement.call( this, config );
- OO.ui.LabelElement.call( this, config );
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.IndicatorElement.call( this, config );
+ OO.ui.mixin.PendingElement.call( this, $.extend( {}, config, { $pending: this.$input } ) );
+ OO.ui.mixin.LabelElement.call( this, config );
// Properties
+ this.type = this.getSaneType( config );
this.readOnly = false;
this.multiline = !!config.multiline;
this.autosize = !!config.autosize;
- this.maxRows = config.maxRows;
+ this.minRows = config.rows !== undefined ? config.rows : '';
+ this.maxRows = config.maxRows || Math.max( 2 * ( this.minRows || 0 ), 10 );
this.validate = null;
// Clone for resizing
@@ -12830,13 +15541,17 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
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' } );
+ this.connect( this, {
+ change: 'onChange',
+ disable: 'onDisable'
+ } );
// Initialization
this.$element
- .addClass( 'oo-ui-textInputWidget' )
+ .addClass( 'oo-ui-textInputWidget oo-ui-textInputWidget-type-' + this.type )
.append( this.$icon, this.$indicator );
this.setReadOnly( !!config.readOnly );
+ this.updateSearchIndicator();
if ( config.placeholder ) {
this.$input.attr( 'placeholder', config.placeholder );
}
@@ -12850,6 +15565,24 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
this.$input.attr( 'required', 'required' );
this.$input.attr( 'aria-required', 'true' );
}
+ if ( config.autocomplete === false ) {
+ this.$input.attr( 'autocomplete', 'off' );
+ // Turning off autocompletion also disables "form caching" when the user navigates to a
+ // different page and then clicks "Back". Re-enable it when leaving. Borrowed from jQuery UI.
+ $( window ).on( {
+ beforeunload: function () {
+ this.$input.removeAttr( 'autocomplete' );
+ }.bind( this ),
+ pageshow: function () {
+ // Browsers don't seem to actually fire this event on "Back", they instead just reload the
+ // whole page... it shouldn't hurt, though.
+ this.$input.attr( 'autocomplete', 'off' );
+ }.bind( this )
+ } );
+ }
+ if ( this.multiline && config.rows ) {
+ this.$input.attr( 'rows', config.rows );
+ }
if ( this.label || config.autosize ) {
this.installParentChangeDetector();
}
@@ -12858,12 +15591,12 @@ OO.ui.TextInputWidget = function OoUiTextInputWidget( config ) {
/* Setup */
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 );
+OO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.IndicatorElement );
+OO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.PendingElement );
+OO.mixinClass( OO.ui.TextInputWidget, OO.ui.mixin.LabelElement );
-/* Static properties */
+/* Static Properties */
OO.ui.TextInputWidget.static.validationPatterns = {
'non-empty': /.+/,
@@ -12905,6 +15638,10 @@ OO.ui.TextInputWidget.prototype.onIconMouseDown = function ( e ) {
*/
OO.ui.TextInputWidget.prototype.onIndicatorMouseDown = function ( e ) {
if ( e.which === 1 ) {
+ if ( this.type === 'search' ) {
+ // Clear the text field
+ this.setValue( '' );
+ }
this.$input[ 0 ].focus();
return false;
}
@@ -12953,11 +15690,22 @@ OO.ui.TextInputWidget.prototype.onElementAttach = function () {
* @private
*/
OO.ui.TextInputWidget.prototype.onChange = function () {
+ this.updateSearchIndicator();
this.setValidityFlag();
this.adjustSize();
};
/**
+ * Handle disable events.
+ *
+ * @param {boolean} disabled Element is disabled
+ * @private
+ */
+OO.ui.TextInputWidget.prototype.onDisable = function () {
+ this.updateSearchIndicator();
+};
+
+/**
* Check if the input is {@link #readOnly read-only}.
*
* @return {boolean}
@@ -12975,6 +15723,7 @@ OO.ui.TextInputWidget.prototype.isReadOnly = function () {
OO.ui.TextInputWidget.prototype.setReadOnly = function ( state ) {
this.readOnly = !!state;
this.$input.prop( 'readOnly', this.readOnly );
+ this.updateSearchIndicator();
return this;
};
@@ -13004,7 +15753,7 @@ OO.ui.TextInputWidget.prototype.installParentChangeDetector = function () {
}
// Find topmost node in the tree
- topmostNode = this.$element[0];
+ topmostNode = this.$element[ 0 ];
while ( topmostNode.parentNode ) {
topmostNode = topmostNode.parentNode;
}
@@ -13038,7 +15787,7 @@ OO.ui.TextInputWidget.prototype.installParentChangeDetector = function () {
};
// Create a fake parent and observe it
- fakeParentNode = $( '<div>' ).append( this.$element )[0];
+ fakeParentNode = $( '<div>' ).append( topmostNode )[ 0 ];
mutationObserver.observe( fakeParentNode, { childList: true } );
} else {
// Using the DOMNodeInsertedIntoDocument event is much nicer and less magical, and works for
@@ -13060,7 +15809,7 @@ OO.ui.TextInputWidget.prototype.adjustSize = function () {
if ( this.multiline && this.autosize && this.$input.val() !== this.valCache ) {
this.$clone
.val( this.$input.val() )
- .attr( 'rows', '' )
+ .attr( 'rows', this.minRows )
// Set inline height property to 0 to measure scroll height
.css( 'height', 0 );
@@ -13102,10 +15851,26 @@ OO.ui.TextInputWidget.prototype.adjustSize = function () {
/**
* @inheritdoc
- * @private
+ * @protected
*/
OO.ui.TextInputWidget.prototype.getInputElement = function ( config ) {
- return config.multiline ? $( '<textarea>' ) : $( '<input type="' + config.type + '" />' );
+ return config.multiline ?
+ $( '<textarea>' ) :
+ $( '<input type="' + this.getSaneType( config ) + '" />' );
+};
+
+/**
+ * Get sanitized value for 'type' for given config.
+ *
+ * @param {Object} config Configuration options
+ * @return {string|null}
+ * @private
+ */
+OO.ui.TextInputWidget.prototype.getSaneType = function ( config ) {
+ var type = [ 'text', 'password', 'search', 'email', 'url' ].indexOf( config.type ) !== -1 ?
+ config.type :
+ 'text';
+ return config.multiline ? 'multiline' : type;
};
/**
@@ -13137,6 +15902,23 @@ OO.ui.TextInputWidget.prototype.select = function () {
};
/**
+ * Focus the input and move the cursor to the end.
+ */
+OO.ui.TextInputWidget.prototype.moveCursorToEnd = function () {
+ var textRange,
+ element = this.$input[ 0 ];
+ this.focus();
+ if ( element.selectionStart !== undefined ) {
+ element.selectionStart = element.selectionEnd = element.value.length;
+ } else if ( element.createTextRange ) {
+ // IE 8 and below
+ textRange = element.createTextRange();
+ textRange.collapse( false );
+ textRange.select();
+ }
+};
+
+/**
* Set the validation pattern.
*
* The validation pattern is either a regular expression, a function, or the symbolic name of a
@@ -13173,7 +15955,11 @@ OO.ui.TextInputWidget.prototype.setValidityFlag = function ( isValid ) {
if ( isValid !== undefined ) {
setFlag( isValid );
} else {
- this.isValid().done( setFlag );
+ this.getValidity().then( function () {
+ setFlag( true );
+ }, function () {
+ setFlag( false );
+ } );
}
};
@@ -13183,11 +15969,14 @@ OO.ui.TextInputWidget.prototype.setValidityFlag = function ( isValid ) {
* 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}.
*
+ * @deprecated
* @return {jQuery.Promise} A promise that resolves to a boolean `true` if the value is valid.
*/
OO.ui.TextInputWidget.prototype.isValid = function () {
+ var result;
+
if ( this.validate instanceof Function ) {
- var result = this.validate( this.getValue() );
+ result = this.validate( this.getValue() );
if ( $.isFunction( result.promise ) ) {
return result.promise();
} else {
@@ -13199,6 +15988,50 @@ OO.ui.TextInputWidget.prototype.isValid = function () {
};
/**
+ * Get the validity of current value.
+ *
+ * This method returns a promise that resolves if the value is valid and rejects if
+ * it isn't. Uses the {@link #validate validation pattern} to check for validity.
+ *
+ * @return {jQuery.Promise} A promise that resolves if the value is valid, rejects if not.
+ */
+OO.ui.TextInputWidget.prototype.getValidity = function () {
+ var result, promise;
+
+ function rejectOrResolve( valid ) {
+ if ( valid ) {
+ return $.Deferred().resolve().promise();
+ } else {
+ return $.Deferred().reject().promise();
+ }
+ }
+
+ if ( this.validate instanceof Function ) {
+ result = this.validate( this.getValue() );
+
+ if ( $.isFunction( result.promise ) ) {
+ promise = $.Deferred();
+
+ result.then( function ( valid ) {
+ if ( valid ) {
+ promise.resolve();
+ } else {
+ promise.reject();
+ }
+ }, function () {
+ promise.reject();
+ } );
+
+ return promise.promise();
+ } else {
+ return rejectOrResolve( result );
+ }
+ } else {
+ return rejectOrResolve( this.getValue().match( this.validate ) );
+ }
+};
+
+/**
* Set the position of the inline label relative to that of the value: `‘before’` or `‘after’`.
*
* @param {string} labelPosition Label position, 'before' or 'after'
@@ -13224,7 +16057,6 @@ OO.ui.TextInputWidget.prototype.setPosition =
* 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 () {
@@ -13234,20 +16066,33 @@ OO.ui.TextInputWidget.prototype.updatePosition = function () {
.toggleClass( 'oo-ui-textInputWidget-labelPosition-after', !!this.label && after )
.toggleClass( 'oo-ui-textInputWidget-labelPosition-before', !!this.label && !after );
- if ( this.label ) {
- this.positionLabel();
- }
+ this.positionLabel();
return this;
};
/**
+ * Update the 'clear' indicator displayed on type: 'search' text fields, hiding it when the field is
+ * already empty or when it's not editable.
+ */
+OO.ui.TextInputWidget.prototype.updateSearchIndicator = function () {
+ if ( this.type === 'search' ) {
+ if ( this.getValue() === '' || this.isDisabled() || this.isReadOnly() ) {
+ this.setIndicator( null );
+ } else {
+ this.setIndicator( 'clear' );
+ }
+ }
+};
+
+/**
* Position the label by setting the correct padding on the input.
*
* @private
* @chainable
*/
OO.ui.TextInputWidget.prototype.positionLabel = function () {
+ var after, rtl, property;
// Clear old values
this.$input
// Clear old values if present
@@ -13263,9 +16108,9 @@ OO.ui.TextInputWidget.prototype.positionLabel = function () {
return;
}
- var after = this.labelPosition === 'after',
- rtl = this.$element.css( 'direction' ) === 'rtl',
- property = after === rtl ? 'padding-left' : 'padding-right';
+ 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 ) );
@@ -13273,6 +16118,30 @@ OO.ui.TextInputWidget.prototype.positionLabel = function () {
};
/**
+ * @inheritdoc
+ */
+OO.ui.TextInputWidget.prototype.gatherPreInfuseState = function ( node ) {
+ var
+ state = OO.ui.TextInputWidget.parent.prototype.gatherPreInfuseState.call( this, node ),
+ $input = $( node ).find( '.oo-ui-inputWidget-input' );
+ state.$input = $input; // shortcut for performance, used in InputWidget
+ if ( this.multiline ) {
+ state.scrollTop = $input.scrollTop();
+ }
+ return state;
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.TextInputWidget.prototype.restorePreInfuseState = function ( state ) {
+ OO.ui.TextInputWidget.parent.prototype.restorePreInfuseState.call( this, state );
+ if ( state.scrollTop !== undefined ) {
+ this.$input.scrollTop( state.scrollTop );
+ }
+};
+
+/**
* 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:
@@ -13320,11 +16189,11 @@ OO.ui.TextInputWidget.prototype.positionLabel = function () {
*
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
- * @cfg {Object} [menu] Configuration options to pass to the {@link OO.ui.MenuSelectWidget menu select widget}.
+ * @cfg {Object} [menu] Configuration options to pass to the {@link OO.ui.FloatingMenuSelectWidget 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
@@ -13335,13 +16204,13 @@ OO.ui.ComboBoxWidget = function OoUiComboBoxWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.ComboBoxWidget.super.call( this, config );
+ OO.ui.ComboBoxWidget.parent.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 } ) );
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$indicator } ) );
// Properties
this.$overlay = config.$overlay || this.$element;
@@ -13357,10 +16226,11 @@ OO.ui.ComboBoxWidget = function OoUiComboBoxWidget( config ) {
role: 'combobox',
'aria-autocomplete': 'list'
} );
- this.menu = new OO.ui.TextInputMenuSelectWidget( this.input, $.extend(
+ this.menu = new OO.ui.FloatingMenuSelectWidget( $.extend(
{
widget: this,
input: this.input,
+ $container: this.input.$element,
disabled: this.isDisabled()
},
config.menu
@@ -13390,19 +16260,27 @@ OO.ui.ComboBoxWidget = function OoUiComboBoxWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.ComboBoxWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.ComboBoxWidget, OO.ui.TabIndexedElement );
+OO.mixinClass( OO.ui.ComboBoxWidget, OO.ui.mixin.TabIndexedElement );
/* Methods */
/**
* Get the combobox's menu.
- * @return {OO.ui.TextInputMenuSelectWidget} Menu widget
+ * @return {OO.ui.FloatingMenuSelectWidget} Menu widget
*/
OO.ui.ComboBoxWidget.prototype.getMenu = function () {
return this.menu;
};
/**
+ * Get the combobox's text input widget.
+ * @return {OO.ui.TextInputWidget} Text input widget
+ */
+OO.ui.ComboBoxWidget.prototype.getInput = function () {
+ return this.input;
+};
+
+/**
* Handle input change events.
*
* @private
@@ -13424,7 +16302,6 @@ OO.ui.ComboBoxWidget.prototype.onInputChange = function ( value ) {
/**
* Handle mouse click events.
*
- *
* @private
* @param {jQuery.Event} e Mouse click event
*/
@@ -13439,7 +16316,6 @@ OO.ui.ComboBoxWidget.prototype.onClick = function ( e ) {
/**
* Handle key press events.
*
- *
* @private
* @param {jQuery.Event} e Key press event
*/
@@ -13491,7 +16367,7 @@ OO.ui.ComboBoxWidget.prototype.onMenuItemsChange = function () {
*/
OO.ui.ComboBoxWidget.prototype.setDisabled = function ( disabled ) {
// Parent method
- OO.ui.ComboBoxWidget.super.prototype.setDisabled.call( this, disabled );
+ OO.ui.ComboBoxWidget.parent.prototype.setDisabled.call( this, disabled );
if ( this.input ) {
this.input.setDisabled( this.isDisabled() );
@@ -13532,10 +16408,9 @@ OO.ui.ComboBoxWidget.prototype.setDisabled = function ( disabled ) {
* ] );
* $( 'body' ).append( fieldset.$element );
*
- *
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.LabelElement
+ * @mixins OO.ui.mixin.LabelElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -13547,11 +16422,11 @@ OO.ui.LabelWidget = function OoUiLabelWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.LabelWidget.super.call( this, config );
+ OO.ui.LabelWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.LabelElement.call( this, $.extend( {}, config, { $label: this.$element } ) );
- OO.ui.TitledElement.call( this, config );
+ OO.ui.mixin.LabelElement.call( this, $.extend( {}, config, { $label: this.$element } ) );
+ OO.ui.mixin.TitledElement.call( this, config );
// Properties
this.input = config.input;
@@ -13568,8 +16443,8 @@ OO.ui.LabelWidget = function OoUiLabelWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.LabelWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.LabelWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.LabelWidget, OO.ui.TitledElement );
+OO.mixinClass( OO.ui.LabelWidget, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.LabelWidget, OO.ui.mixin.TitledElement );
/* Static Properties */
@@ -13598,8 +16473,8 @@ OO.ui.LabelWidget.prototype.onClick = function () {
*
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.LabelElement
- * @mixins OO.ui.FlaggedElement
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.FlaggedElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -13609,12 +16484,12 @@ OO.ui.OptionWidget = function OoUiOptionWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.OptionWidget.super.call( this, config );
+ OO.ui.OptionWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.ItemWidget.call( this );
- OO.ui.LabelElement.call( this, config );
- OO.ui.FlaggedElement.call( this, config );
+ OO.ui.mixin.ItemWidget.call( this );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.FlaggedElement.call( this, config );
// Properties
this.selected = false;
@@ -13625,6 +16500,7 @@ OO.ui.OptionWidget = function OoUiOptionWidget( config ) {
this.$element
.data( 'oo-ui-optionWidget', this )
.attr( 'role', 'option' )
+ .attr( 'aria-selected', 'false' )
.addClass( 'oo-ui-optionWidget' )
.append( this.$label );
};
@@ -13632,9 +16508,9 @@ OO.ui.OptionWidget = function OoUiOptionWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.OptionWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.ItemWidget );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.FlaggedElement );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.ItemWidget );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.OptionWidget, OO.ui.mixin.FlaggedElement );
/* Static Properties */
@@ -13654,7 +16530,7 @@ OO.ui.OptionWidget.static.scrollIntoViewOnSelect = false;
* @return {boolean} Item is selectable
*/
OO.ui.OptionWidget.prototype.isSelectable = function () {
- return this.constructor.static.selectable && !this.isDisabled();
+ return this.constructor.static.selectable && !this.isDisabled() && this.isVisible();
};
/**
@@ -13665,7 +16541,7 @@ OO.ui.OptionWidget.prototype.isSelectable = function () {
* @return {boolean} Item is highlightable
*/
OO.ui.OptionWidget.prototype.isHighlightable = function () {
- return this.constructor.static.highlightable && !this.isDisabled();
+ return this.constructor.static.highlightable && !this.isDisabled() && this.isVisible();
};
/**
@@ -13675,7 +16551,7 @@ OO.ui.OptionWidget.prototype.isHighlightable = function () {
* @return {boolean} Item is pressable
*/
OO.ui.OptionWidget.prototype.isPressable = function () {
- return this.constructor.static.pressable && !this.isDisabled();
+ return this.constructor.static.pressable && !this.isDisabled() && this.isVisible();
};
/**
@@ -13768,7 +16644,7 @@ OO.ui.OptionWidget.prototype.setPressed = function ( state ) {
/**
* 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}.
+ * with an {@link OO.ui.mixin.IconElement icon} and/or {@link OO.ui.mixin.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].
@@ -13795,19 +16671,19 @@ OO.ui.OptionWidget.prototype.setPressed = function ( state ) {
*
* @class
* @extends OO.ui.OptionWidget
- * @mixins OO.ui.IconElement
- * @mixins OO.ui.IndicatorElement
+ * @mixins OO.ui.mixin.IconElement
+ * @mixins OO.ui.mixin.IndicatorElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
OO.ui.DecoratedOptionWidget = function OoUiDecoratedOptionWidget( config ) {
// Parent constructor
- OO.ui.DecoratedOptionWidget.super.call( this, config );
+ OO.ui.DecoratedOptionWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.IconElement.call( this, config );
- OO.ui.IndicatorElement.call( this, config );
+ OO.ui.mixin.IconElement.call( this, config );
+ OO.ui.mixin.IndicatorElement.call( this, config );
// Initialization
this.$element
@@ -13819,11 +16695,11 @@ OO.ui.DecoratedOptionWidget = function OoUiDecoratedOptionWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.DecoratedOptionWidget, OO.ui.OptionWidget );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.IconElement );
-OO.mixinClass( OO.ui.OptionWidget, OO.ui.IndicatorElement );
+OO.mixinClass( OO.ui.DecoratedOptionWidget, OO.ui.mixin.IconElement );
+OO.mixinClass( OO.ui.DecoratedOptionWidget, OO.ui.mixin.IndicatorElement );
/**
- * ButtonOptionWidget is a special type of {@link OO.ui.ButtonElement button element} that
+ * ButtonOptionWidget is a special type of {@link OO.ui.mixin.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.
@@ -13832,22 +16708,27 @@ OO.mixinClass( OO.ui.OptionWidget, OO.ui.IndicatorElement );
*
* @class
* @extends OO.ui.DecoratedOptionWidget
- * @mixins OO.ui.ButtonElement
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.ButtonElement
+ * @mixins OO.ui.mixin.TabIndexedElement
+ * @mixins OO.ui.mixin.TitledElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
OO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( config ) {
// Configuration initialization
- config = $.extend( { tabIndex: -1 }, config );
+ config = config || {};
// Parent constructor
- OO.ui.ButtonOptionWidget.super.call( this, config );
+ OO.ui.ButtonOptionWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.ButtonElement.call( this, config );
- OO.ui.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$button } ) );
+ OO.ui.mixin.ButtonElement.call( this, config );
+ OO.ui.mixin.TitledElement.call( this, $.extend( {}, config, { $titled: this.$button } ) );
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, {
+ $tabIndexed: this.$button,
+ tabIndex: -1
+ } ) );
// Initialization
this.$element.addClass( 'oo-ui-buttonOptionWidget' );
@@ -13858,8 +16739,9 @@ OO.ui.ButtonOptionWidget = function OoUiButtonOptionWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.ButtonOptionWidget, OO.ui.DecoratedOptionWidget );
-OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.ButtonElement );
-OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.TabIndexedElement );
+OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.ButtonElement );
+OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.TitledElement );
+OO.mixinClass( OO.ui.ButtonOptionWidget, OO.ui.mixin.TabIndexedElement );
/* Static Properties */
@@ -13874,7 +16756,7 @@ OO.ui.ButtonOptionWidget.static.highlightable = false;
* @inheritdoc
*/
OO.ui.ButtonOptionWidget.prototype.setSelected = function ( state ) {
- OO.ui.ButtonOptionWidget.super.prototype.setSelected.call( this, state );
+ OO.ui.ButtonOptionWidget.parent.prototype.setSelected.call( this, state );
if ( this.constructor.static.selectable ) {
this.setActive( state );
@@ -13904,11 +16786,19 @@ OO.ui.RadioOptionWidget = function OoUiRadioOptionWidget( config ) {
this.radio = new OO.ui.RadioInputWidget( { value: config.data, tabIndex: -1 } );
// Parent constructor
- OO.ui.RadioOptionWidget.super.call( this, config );
+ OO.ui.RadioOptionWidget.parent.call( this, config );
+
+ // Events
+ this.radio.$input.on( 'focus', this.onInputFocus.bind( this ) );
// Initialization
+ // Remove implicit role, we're handling it ourselves
+ this.radio.$input.attr( 'role', 'presentation' );
this.$element
.addClass( 'oo-ui-radioOptionWidget' )
+ .attr( 'role', 'radio' )
+ .attr( 'aria-checked', 'false' )
+ .removeAttr( 'aria-selected' )
.prepend( this.radio.$element );
};
@@ -13929,12 +16819,24 @@ OO.ui.RadioOptionWidget.static.tagName = 'label';
/* Methods */
/**
+ * @param {jQuery.Event} e Focus event
+ * @private
+ */
+OO.ui.RadioOptionWidget.prototype.onInputFocus = function () {
+ this.radio.$input.blur();
+ this.$element.parent().focus();
+};
+
+/**
* @inheritdoc
*/
OO.ui.RadioOptionWidget.prototype.setSelected = function ( state ) {
- OO.ui.RadioOptionWidget.super.prototype.setSelected.call( this, state );
+ OO.ui.RadioOptionWidget.parent.prototype.setSelected.call( this, state );
this.radio.setSelected( state );
+ this.$element
+ .attr( 'aria-checked', state.toString() )
+ .removeAttr( 'aria-selected' );
return this;
};
@@ -13943,7 +16845,7 @@ OO.ui.RadioOptionWidget.prototype.setSelected = function ( state ) {
* @inheritdoc
*/
OO.ui.RadioOptionWidget.prototype.setDisabled = function ( disabled ) {
- OO.ui.RadioOptionWidget.super.prototype.setDisabled.call( this, disabled );
+ OO.ui.RadioOptionWidget.parent.prototype.setDisabled.call( this, disabled );
this.radio.setDisabled( this.isDisabled() );
@@ -13968,7 +16870,7 @@ OO.ui.MenuOptionWidget = function OoUiMenuOptionWidget( config ) {
config = $.extend( { icon: 'check' }, config );
// Parent constructor
- OO.ui.MenuOptionWidget.super.call( this, config );
+ OO.ui.MenuOptionWidget.parent.call( this, config );
// Initialization
this.$element
@@ -14015,7 +16917,6 @@ OO.ui.MenuOptionWidget.static.scrollIntoViewOnSelect = true;
* } );
* $( 'body' ).append( myDropdown.$element );
*
- *
* @class
* @extends OO.ui.DecoratedOptionWidget
*
@@ -14024,7 +16925,7 @@ OO.ui.MenuOptionWidget.static.scrollIntoViewOnSelect = true;
*/
OO.ui.MenuSectionOptionWidget = function OoUiMenuSectionOptionWidget( config ) {
// Parent constructor
- OO.ui.MenuSectionOptionWidget.super.call( this, config );
+ OO.ui.MenuSectionOptionWidget.parent.call( this, config );
// Initialization
this.$element.addClass( 'oo-ui-menuSectionOptionWidget' );
@@ -14060,7 +16961,7 @@ OO.ui.OutlineOptionWidget = function OoUiOutlineOptionWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.OutlineOptionWidget.super.call( this, config );
+ OO.ui.OutlineOptionWidget.parent.call( this, config );
// Properties
this.level = 0;
@@ -14189,7 +17090,7 @@ OO.ui.TabOptionWidget = function OoUiTabOptionWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.TabOptionWidget.super.call( this, config );
+ OO.ui.TabOptionWidget.parent.call( this, config );
// Initialization
this.$element.addClass( 'oo-ui-tabOptionWidget' );
@@ -14224,7 +17125,8 @@ OO.ui.TabOptionWidget.static.highlightable = false;
*
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.LabelElement
+ * @mixins OO.ui.mixin.LabelElement
+ * @mixins OO.ui.mixin.ClippableElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -14243,6 +17145,7 @@ OO.ui.TabOptionWidget.static.highlightable = false;
* [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 {jQuery} [$footer] Content to append to the popup's footer
* @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]
@@ -14257,18 +17160,22 @@ OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.PopupWidget.super.call( this, config );
+ OO.ui.PopupWidget.parent.call( this, config );
// Properties (must be set before ClippableElement constructor call)
this.$body = $( '<div>' );
+ this.$popup = $( '<div>' );
// Mixin constructors
- OO.ui.LabelElement.call( this, config );
- OO.ui.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$body } ) );
+ OO.ui.mixin.LabelElement.call( this, config );
+ OO.ui.mixin.ClippableElement.call( this, $.extend( {}, config, {
+ $clippable: this.$body,
+ $clippableContainer: this.$popup
+ } ) );
// Properties
- this.$popup = $( '<div>' );
this.$head = $( '<div>' );
+ this.$footer = $( '<div>' );
this.$anchor = $( '<div>' );
// If undefined, will be computed lazily in updateDimensions()
this.$container = config.$container;
@@ -14294,12 +17201,16 @@ OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
this.$head
.addClass( 'oo-ui-popupWidget-head' )
.append( this.$label, this.closeButton.$element );
+ this.$footer.addClass( 'oo-ui-popupWidget-footer' );
if ( !config.head ) {
this.$head.addClass( 'oo-ui-element-hidden' );
}
+ if ( !config.$footer ) {
+ this.$footer.addClass( 'oo-ui-element-hidden' );
+ }
this.$popup
.addClass( 'oo-ui-popupWidget-popup' )
- .append( this.$head, this.$body );
+ .append( this.$head, this.$body, this.$footer );
this.$element
.addClass( 'oo-ui-popupWidget' )
.append( this.$popup, this.$anchor );
@@ -14307,6 +17218,9 @@ OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
if ( config.$content instanceof jQuery ) {
this.$body.append( config.$content );
}
+ if ( config.$footer instanceof jQuery ) {
+ this.$footer.append( config.$footer );
+ }
if ( config.padded ) {
this.$body.addClass( 'oo-ui-popupWidget-body-padded' );
}
@@ -14321,8 +17235,8 @@ OO.ui.PopupWidget = function OoUiPopupWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.PopupWidget, OO.ui.Widget );
-OO.mixinClass( OO.ui.PopupWidget, OO.ui.LabelElement );
-OO.mixinClass( OO.ui.PopupWidget, OO.ui.ClippableElement );
+OO.mixinClass( OO.ui.PopupWidget, OO.ui.mixin.LabelElement );
+OO.mixinClass( OO.ui.PopupWidget, OO.ui.mixin.ClippableElement );
/* Methods */
@@ -14349,7 +17263,7 @@ OO.ui.PopupWidget.prototype.onMouseDown = function ( e ) {
*/
OO.ui.PopupWidget.prototype.bindMouseDownListener = function () {
// Capture clicks outside popup
- this.getElementWindow().addEventListener( 'mousedown', this.onMouseDownHandler, true );
+ OO.ui.addCaptureEventListener( this.getElementWindow(), 'mousedown', this.onMouseDownHandler );
};
/**
@@ -14369,7 +17283,7 @@ OO.ui.PopupWidget.prototype.onCloseButtonClick = function () {
* @private
*/
OO.ui.PopupWidget.prototype.unbindMouseDownListener = function () {
- this.getElementWindow().removeEventListener( 'mousedown', this.onMouseDownHandler, true );
+ OO.ui.removeCaptureEventListener( this.getElementWindow(), 'mousedown', this.onMouseDownHandler );
};
/**
@@ -14395,7 +17309,7 @@ OO.ui.PopupWidget.prototype.onDocumentKeyDown = function ( e ) {
* @private
*/
OO.ui.PopupWidget.prototype.bindKeyDownListener = function () {
- this.getElementWindow().addEventListener( 'keydown', this.onDocumentKeyDownHandler, true );
+ OO.ui.addCaptureEventListener( this.getElementWindow(), 'keydown', this.onDocumentKeyDownHandler );
};
/**
@@ -14404,7 +17318,7 @@ OO.ui.PopupWidget.prototype.bindKeyDownListener = function () {
* @private
*/
OO.ui.PopupWidget.prototype.unbindKeyDownListener = function () {
- this.getElementWindow().removeEventListener( 'keydown', this.onDocumentKeyDownHandler, true );
+ OO.ui.removeCaptureEventListener( this.getElementWindow(), 'keydown', this.onDocumentKeyDownHandler );
};
/**
@@ -14438,12 +17352,13 @@ OO.ui.PopupWidget.prototype.hasAnchor = function () {
* @inheritdoc
*/
OO.ui.PopupWidget.prototype.toggle = function ( show ) {
+ var change;
show = show === undefined ? !this.isVisible() : !!show;
- var change = show !== this.isVisible();
+ change = show !== this.isVisible();
// Parent method
- OO.ui.PopupWidget.super.prototype.toggle.call( this, show );
+ OO.ui.PopupWidget.parent.prototype.toggle.call( this, show );
if ( change ) {
if ( show ) {
@@ -14640,7 +17555,7 @@ OO.ui.ProgressBarWidget = function OoUiProgressBarWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.ProgressBarWidget.super.call( this, config );
+ OO.ui.ProgressBarWidget.parent.call( this, config );
// Properties
this.$bar = $( '<div>' );
@@ -14698,8 +17613,8 @@ OO.ui.ProgressBarWidget.prototype.setProgress = function ( 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.
+ * and a menu of search results, which is displayed beneath the query
+ * field. Unlike {@link OO.ui.mixin.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.
*
@@ -14721,7 +17636,7 @@ OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.SearchWidget.super.call( this, config );
+ OO.ui.SearchWidget.parent.call( this, config );
// Properties
this.query = new OO.ui.TextInputWidget( {
@@ -14738,10 +17653,6 @@ OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
change: 'onQueryChange',
enter: 'onQueryEnter'
} );
- this.results.connect( this, {
- highlight: 'onResultsHighlight',
- select: 'onResultsSelect'
- } );
this.query.$input.on( 'keydown', this.onQueryKeydown.bind( this ) );
// Initialization
@@ -14760,28 +17671,6 @@ OO.ui.SearchWidget = function OoUiSearchWidget( config ) {
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
- */
-
/* Methods */
/**
@@ -14821,38 +17710,16 @@ OO.ui.SearchWidget.prototype.onQueryChange = function () {
/**
* Handle select widget enter key events.
*
- * Selects highlighted item.
+ * Chooses highlighted item.
*
* @private
* @param {string} value New value
*/
OO.ui.SearchWidget.prototype.onQueryEnter = function () {
- // Reset
- this.results.selectItem( this.results.getHighlightedItem() );
-};
-
-/**
- * Handle select widget highlight events.
- *
- * @private
- * @deprecated Connect straight to getResults() events instead
- * @param {OO.ui.OptionWidget} item Highlighted item
- * @fires highlight
- */
-OO.ui.SearchWidget.prototype.onResultsHighlight = function ( item ) {
- this.emit( 'highlight', item ? item.getData() : null );
-};
-
-/**
- * Handle select widget select events.
- *
- * @private
- * @deprecated Connect straight to getResults() events instead
- * @param {OO.ui.OptionWidget} item Selected item
- * @fires select
- */
-OO.ui.SearchWidget.prototype.onResultsSelect = function ( item ) {
- this.emit( 'select', item ? item.getData() : null );
+ var highlightedItem = this.results.getHighlightedItem();
+ if ( highlightedItem ) {
+ this.results.chooseItem( highlightedItem );
+ }
};
/**
@@ -14907,7 +17774,7 @@ OO.ui.SearchWidget.prototype.getResults = function () {
* @abstract
* @class
* @extends OO.ui.Widget
- * @mixins OO.ui.GroupElement
+ * @mixins OO.ui.mixin.GroupWidget
*
* @constructor
* @param {Object} [config] Configuration options
@@ -14921,10 +17788,10 @@ OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
config = config || {};
// Parent constructor
- OO.ui.SelectWidget.super.call( this, config );
+ OO.ui.SelectWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.GroupWidget.call( this, $.extend( {}, config, { $group: this.$element } ) );
+ OO.ui.mixin.GroupWidget.call( this, $.extend( {}, config, { $group: this.$element } ) );
// Properties
this.pressed = false;
@@ -14932,8 +17799,14 @@ OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
this.onMouseUpHandler = this.onMouseUp.bind( this );
this.onMouseMoveHandler = this.onMouseMove.bind( this );
this.onKeyDownHandler = this.onKeyDown.bind( this );
+ this.onKeyPressHandler = this.onKeyPress.bind( this );
+ this.keyPressBuffer = '';
+ this.keyPressBufferTimer = null;
// Events
+ this.connect( this, {
+ toggle: 'onToggle'
+ } );
this.$element.on( {
mousedown: this.onMouseDown.bind( this ),
mouseover: this.onMouseOver.bind( this ),
@@ -14954,8 +17827,13 @@ OO.ui.SelectWidget = function OoUiSelectWidget( config ) {
OO.inheritClass( OO.ui.SelectWidget, OO.ui.Widget );
// Need to mixin base class as well
-OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupElement );
-OO.mixinClass( OO.ui.SelectWidget, OO.ui.GroupWidget );
+OO.mixinClass( OO.ui.SelectWidget, OO.ui.mixin.GroupElement );
+OO.mixinClass( OO.ui.SelectWidget, OO.ui.mixin.GroupWidget );
+
+/* Static */
+OO.ui.SelectWidget.static.passAllFilter = function () {
+ return true;
+};
/* Events */
@@ -15025,15 +17903,15 @@ OO.ui.SelectWidget.prototype.onMouseDown = function ( e ) {
if ( item && item.isSelectable() ) {
this.pressItem( item );
this.selecting = item;
- this.getElementDocument().addEventListener(
+ OO.ui.addCaptureEventListener(
+ this.getElementDocument(),
'mouseup',
- this.onMouseUpHandler,
- true
+ this.onMouseUpHandler
);
- this.getElementDocument().addEventListener(
+ OO.ui.addCaptureEventListener(
+ this.getElementDocument(),
'mousemove',
- this.onMouseMoveHandler,
- true
+ this.onMouseMoveHandler
);
}
}
@@ -15062,16 +17940,10 @@ OO.ui.SelectWidget.prototype.onMouseUp = function ( e ) {
this.selecting = null;
}
- this.getElementDocument().removeEventListener(
- 'mouseup',
- this.onMouseUpHandler,
- true
- );
- this.getElementDocument().removeEventListener(
- 'mousemove',
- this.onMouseMoveHandler,
- true
- );
+ OO.ui.removeCaptureEventListener( this.getElementDocument(), 'mouseup',
+ this.onMouseUpHandler );
+ OO.ui.removeCaptureEventListener( this.getElementDocument(), 'mousemove',
+ this.onMouseMoveHandler );
return false;
};
@@ -15146,11 +18018,13 @@ OO.ui.SelectWidget.prototype.onKeyDown = function ( e ) {
break;
case OO.ui.Keys.UP:
case OO.ui.Keys.LEFT:
+ this.clearKeyPressBuffer();
nextItem = this.getRelativeSelectableItem( currentItem, -1 );
handled = true;
break;
case OO.ui.Keys.DOWN:
case OO.ui.Keys.RIGHT:
+ this.clearKeyPressBuffer();
nextItem = this.getRelativeSelectableItem( currentItem, 1 );
handled = true;
break;
@@ -15160,6 +18034,7 @@ OO.ui.SelectWidget.prototype.onKeyDown = function ( e ) {
currentItem.setHighlighted( false );
}
this.unbindKeyDownListener();
+ this.unbindKeyPressListener();
// Don't prevent tabbing away / defocusing
handled = false;
break;
@@ -15188,7 +18063,7 @@ OO.ui.SelectWidget.prototype.onKeyDown = function ( e ) {
* @protected
*/
OO.ui.SelectWidget.prototype.bindKeyDownListener = function () {
- this.getElementWindow().addEventListener( 'keydown', this.onKeyDownHandler, true );
+ OO.ui.addCaptureEventListener( this.getElementWindow(), 'keydown', this.onKeyDownHandler );
};
/**
@@ -15197,7 +18072,141 @@ OO.ui.SelectWidget.prototype.bindKeyDownListener = function () {
* @protected
*/
OO.ui.SelectWidget.prototype.unbindKeyDownListener = function () {
- this.getElementWindow().removeEventListener( 'keydown', this.onKeyDownHandler, true );
+ OO.ui.removeCaptureEventListener( this.getElementWindow(), 'keydown', this.onKeyDownHandler );
+};
+
+/**
+ * Clear the key-press buffer
+ *
+ * @protected
+ */
+OO.ui.SelectWidget.prototype.clearKeyPressBuffer = function () {
+ if ( this.keyPressBufferTimer ) {
+ clearTimeout( this.keyPressBufferTimer );
+ this.keyPressBufferTimer = null;
+ }
+ this.keyPressBuffer = '';
+};
+
+/**
+ * Handle key press events.
+ *
+ * @protected
+ * @param {jQuery.Event} e Key press event
+ */
+OO.ui.SelectWidget.prototype.onKeyPress = function ( e ) {
+ var c, filter, item;
+
+ if ( !e.charCode ) {
+ if ( e.keyCode === OO.ui.Keys.BACKSPACE && this.keyPressBuffer !== '' ) {
+ this.keyPressBuffer = this.keyPressBuffer.substr( 0, this.keyPressBuffer.length - 1 );
+ return false;
+ }
+ return;
+ }
+ if ( String.fromCodePoint ) {
+ c = String.fromCodePoint( e.charCode );
+ } else {
+ c = String.fromCharCode( e.charCode );
+ }
+
+ if ( this.keyPressBufferTimer ) {
+ clearTimeout( this.keyPressBufferTimer );
+ }
+ this.keyPressBufferTimer = setTimeout( this.clearKeyPressBuffer.bind( this ), 1500 );
+
+ item = this.getHighlightedItem() || this.getSelectedItem();
+
+ if ( this.keyPressBuffer === c ) {
+ // Common (if weird) special case: typing "xxxx" will cycle through all
+ // the items beginning with "x".
+ if ( item ) {
+ item = this.getRelativeSelectableItem( item, 1 );
+ }
+ } else {
+ this.keyPressBuffer += c;
+ }
+
+ filter = this.getItemMatcher( this.keyPressBuffer, false );
+ if ( !item || !filter( item ) ) {
+ item = this.getRelativeSelectableItem( item, 1, filter );
+ }
+ if ( item ) {
+ if ( item.constructor.static.highlightable ) {
+ this.highlightItem( item );
+ } else {
+ this.chooseItem( item );
+ }
+ item.scrollElementIntoView();
+ }
+
+ return false;
+};
+
+/**
+ * Get a matcher for the specific string
+ *
+ * @protected
+ * @param {string} s String to match against items
+ * @param {boolean} [exact=false] Only accept exact matches
+ * @return {Function} function ( OO.ui.OptionItem ) => boolean
+ */
+OO.ui.SelectWidget.prototype.getItemMatcher = function ( s, exact ) {
+ var re;
+
+ if ( s.normalize ) {
+ s = s.normalize();
+ }
+ s = exact ? s.trim() : s.replace( /^\s+/, '' );
+ re = '^\\s*' + s.replace( /([\\{}()|.?*+\-\^$\[\]])/g, '\\$1' ).replace( /\s+/g, '\\s+' );
+ if ( exact ) {
+ re += '\\s*$';
+ }
+ re = new RegExp( re, 'i' );
+ return function ( item ) {
+ var l = item.getLabel();
+ if ( typeof l !== 'string' ) {
+ l = item.$label.text();
+ }
+ if ( l.normalize ) {
+ l = l.normalize();
+ }
+ return re.test( l );
+ };
+};
+
+/**
+ * Bind key press listener.
+ *
+ * @protected
+ */
+OO.ui.SelectWidget.prototype.bindKeyPressListener = function () {
+ OO.ui.addCaptureEventListener( this.getElementWindow(), 'keypress', this.onKeyPressHandler );
+};
+
+/**
+ * Unbind key down listener.
+ *
+ * If you override this, be sure to call this.clearKeyPressBuffer() from your
+ * implementation.
+ *
+ * @protected
+ */
+OO.ui.SelectWidget.prototype.unbindKeyPressListener = function () {
+ OO.ui.removeCaptureEventListener( this.getElementWindow(), 'keypress', this.onKeyPressHandler );
+ this.clearKeyPressBuffer();
+};
+
+/**
+ * Visibility change handler
+ *
+ * @protected
+ * @param {boolean} visible
+ */
+OO.ui.SelectWidget.prototype.onToggle = function ( visible ) {
+ if ( !visible ) {
+ this.clearKeyPressBuffer();
+ }
};
/**
@@ -15291,6 +18300,62 @@ OO.ui.SelectWidget.prototype.highlightItem = function ( item ) {
};
/**
+ * Fetch an item by its label.
+ *
+ * @param {string} label Label of the item to select.
+ * @param {boolean} [prefix=false] Allow a prefix match, if only a single item matches
+ * @return {OO.ui.Element|null} Item with equivalent label, `null` if none exists
+ */
+OO.ui.SelectWidget.prototype.getItemFromLabel = function ( label, prefix ) {
+ var i, item, found,
+ len = this.items.length,
+ filter = this.getItemMatcher( label, true );
+
+ for ( i = 0; i < len; i++ ) {
+ item = this.items[ i ];
+ if ( item instanceof OO.ui.OptionWidget && item.isSelectable() && filter( item ) ) {
+ return item;
+ }
+ }
+
+ if ( prefix ) {
+ found = null;
+ filter = this.getItemMatcher( label, false );
+ for ( i = 0; i < len; i++ ) {
+ item = this.items[ i ];
+ if ( item instanceof OO.ui.OptionWidget && item.isSelectable() && filter( item ) ) {
+ if ( found ) {
+ return null;
+ }
+ found = item;
+ }
+ }
+ if ( found ) {
+ return found;
+ }
+ }
+
+ return null;
+};
+
+/**
+ * Programmatically select an option by its label. If the item does not exist,
+ * all options will be deselected.
+ *
+ * @param {string} [label] Label of the item to select.
+ * @param {boolean} [prefix=false] Allow a prefix match, if only a single item matches
+ * @fires select
+ * @chainable
+ */
+OO.ui.SelectWidget.prototype.selectItemByLabel = function ( label, prefix ) {
+ var itemFromLabel = this.getItemFromLabel( label, !!prefix );
+ if ( label === undefined || !itemFromLabel ) {
+ return this.selectItem();
+ }
+ return this.selectItem( itemFromLabel );
+};
+
+/**
* 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.
*
@@ -15376,8 +18441,10 @@ OO.ui.SelectWidget.prototype.pressItem = function ( item ) {
* @chainable
*/
OO.ui.SelectWidget.prototype.chooseItem = function ( item ) {
- this.selectItem( item );
- this.emit( 'choose', item );
+ if ( item ) {
+ this.selectItem( item );
+ this.emit( 'choose', item );
+ }
return this;
};
@@ -15390,15 +18457,21 @@ OO.ui.SelectWidget.prototype.chooseItem = function ( item ) {
*
* @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
+ * @param {Function} filter Only consider items for which this function returns
+ * true. Function takes an OO.ui.OptionWidget and returns a boolean.
* @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 ) {
+OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direction, filter ) {
var currentIndex, nextIndex, i,
increase = direction > 0 ? 1 : -1,
len = this.items.length;
+ if ( !$.isFunction( filter ) ) {
+ filter = OO.ui.SelectWidget.static.passAllFilter;
+ }
+
if ( item instanceof OO.ui.OptionWidget ) {
- currentIndex = $.inArray( item, this.items );
+ currentIndex = this.items.indexOf( item );
nextIndex = ( currentIndex + increase + len ) % len;
} else {
// If no item is selected and moving forward, start at the beginning.
@@ -15408,7 +18481,7 @@ OO.ui.SelectWidget.prototype.getRelativeSelectableItem = function ( item, direct
for ( i = 0; i < len; i++ ) {
item = this.items[ nextIndex ];
- if ( item instanceof OO.ui.OptionWidget && item.isSelectable() ) {
+ if ( item instanceof OO.ui.OptionWidget && item.isSelectable() && filter( item ) ) {
return item;
}
nextIndex = ( nextIndex + increase + len ) % len;
@@ -15446,7 +18519,7 @@ OO.ui.SelectWidget.prototype.getFirstSelectableItem = function () {
*/
OO.ui.SelectWidget.prototype.addItems = function ( items, index ) {
// Mixin method
- OO.ui.GroupWidget.prototype.addItems.call( this, items, index );
+ OO.ui.mixin.GroupWidget.prototype.addItems.call( this, items, index );
// Always provide an index, even if it was omitted
this.emit( 'add', items, index === undefined ? this.items.length - items.length - 1 : index );
@@ -15475,7 +18548,7 @@ OO.ui.SelectWidget.prototype.removeItems = function ( items ) {
}
// Mixin method
- OO.ui.GroupWidget.prototype.removeItems.call( this, items );
+ OO.ui.mixin.GroupWidget.prototype.removeItems.call( this, items );
this.emit( 'remove', items );
@@ -15494,7 +18567,7 @@ OO.ui.SelectWidget.prototype.clearItems = function () {
var items = this.items.slice();
// Mixin method
- OO.ui.GroupWidget.prototype.clearItems.call( this );
+ OO.ui.mixin.GroupWidget.prototype.clearItems.call( this );
// Clear selection
this.selectItem( null );
@@ -15540,17 +18613,17 @@ OO.ui.SelectWidget.prototype.clearItems = function () {
*
* @class
* @extends OO.ui.SelectWidget
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
OO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {
// Parent constructor
- OO.ui.ButtonSelectWidget.super.call( this, config );
+ OO.ui.ButtonSelectWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.TabIndexedElement.call( this, config );
+ OO.ui.mixin.TabIndexedElement.call( this, config );
// Events
this.$element.on( {
@@ -15565,7 +18638,7 @@ OO.ui.ButtonSelectWidget = function OoUiButtonSelectWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.ButtonSelectWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.ButtonSelectWidget, OO.ui.TabIndexedElement );
+OO.mixinClass( OO.ui.ButtonSelectWidget, OO.ui.mixin.TabIndexedElement );
/**
* RadioSelectWidget is a {@link OO.ui.SelectWidget select widget} that contains radio
@@ -15573,6 +18646,9 @@ OO.mixinClass( OO.ui.ButtonSelectWidget, OO.ui.TabIndexedElement );
* an interface for adding, removing and selecting options.
* Please see the [OOjs UI documentation on MediaWiki][1] for more information.
*
+ * If you want to use this within a HTML form, such as a OO.ui.FormLayout, use
+ * OO.ui.RadioSelectInputWidget instead.
+ *
* @example
* // A RadioSelectWidget with RadioOptions.
* var option1 = new OO.ui.RadioOptionWidget( {
@@ -15599,17 +18675,17 @@ OO.mixinClass( OO.ui.ButtonSelectWidget, OO.ui.TabIndexedElement );
*
* @class
* @extends OO.ui.SelectWidget
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
OO.ui.RadioSelectWidget = function OoUiRadioSelectWidget( config ) {
// Parent constructor
- OO.ui.RadioSelectWidget.super.call( this, config );
+ OO.ui.RadioSelectWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.TabIndexedElement.call( this, config );
+ OO.ui.mixin.TabIndexedElement.call( this, config );
// Events
this.$element.on( {
@@ -15618,19 +18694,21 @@ OO.ui.RadioSelectWidget = function OoUiRadioSelectWidget( config ) {
} );
// Initialization
- this.$element.addClass( 'oo-ui-radioSelectWidget' );
+ this.$element
+ .addClass( 'oo-ui-radioSelectWidget' )
+ .attr( 'role', 'radiogroup' );
};
/* Setup */
OO.inheritClass( OO.ui.RadioSelectWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.RadioSelectWidget, OO.ui.TabIndexedElement );
+OO.mixinClass( OO.ui.RadioSelectWidget, OO.ui.mixin.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.
+ * and {@link OO.ui.mixin.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.
*
@@ -15649,33 +18727,40 @@ OO.mixinClass( OO.ui.RadioSelectWidget, OO.ui.TabIndexedElement );
*
* @class
* @extends OO.ui.SelectWidget
- * @mixins OO.ui.ClippableElement
+ * @mixins OO.ui.mixin.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.
+ * and {@link OO.ui.mixin.LookupElement LookupElement}
+ * @cfg {jQuery} [$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.CapsuleMultiSelectWidget CapsuleMultiSelectWidget}
+ * @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. For example, if there is a button
+ * that toggles the menu's visibility on click, the menu will be hidden then re-shown when the user clicks
+ * that button, unless the button (or its parent widget) is passed in here.
* @cfg {boolean} [autoHide=true] Hide the menu when the mouse is pressed outside the menu.
+ * @cfg {boolean} [filterFromInput=false] Filter the displayed options from the input
*/
OO.ui.MenuSelectWidget = function OoUiMenuSelectWidget( config ) {
// Configuration initialization
config = config || {};
// Parent constructor
- OO.ui.MenuSelectWidget.super.call( this, config );
+ OO.ui.MenuSelectWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$group } ) );
+ OO.ui.mixin.ClippableElement.call( this, $.extend( {}, config, { $clippable: this.$group } ) );
// Properties
this.newItems = null;
this.autoHide = config.autoHide === undefined || !!config.autoHide;
- this.$input = config.input ? config.input.$input : null;
+ this.filterFromInput = !!config.filterFromInput;
+ this.$input = config.$input ? config.$input : config.input ? config.input.$input : null;
this.$widget = config.widget ? config.widget.$element : null;
this.onDocumentMouseDownHandler = this.onDocumentMouseDown.bind( this );
+ this.onInputEditHandler = OO.ui.debounce( this.updateItemVisibility.bind( this ), 100 );
// Initialization
this.$element
@@ -15692,7 +18777,7 @@ OO.ui.MenuSelectWidget = function OoUiMenuSelectWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.MenuSelectWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.MenuSelectWidget, OO.ui.ClippableElement );
+OO.mixinClass( OO.ui.MenuSelectWidget, OO.ui.mixin.ClippableElement );
/* Methods */
@@ -15723,7 +18808,7 @@ OO.ui.MenuSelectWidget.prototype.onKeyDown = function ( e ) {
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 );
+ OO.ui.MenuSelectWidget.parent.prototype.onKeyDown.call( this, e );
}
break;
case OO.ui.Keys.ESCAPE:
@@ -15739,20 +18824,41 @@ OO.ui.MenuSelectWidget.prototype.onKeyDown = function ( e ) {
}
break;
default:
- OO.ui.MenuSelectWidget.super.prototype.onKeyDown.call( this, e );
+ OO.ui.MenuSelectWidget.parent.prototype.onKeyDown.call( this, e );
return;
}
}
};
/**
+ * Update menu item visibility after input changes.
+ * @protected
+ */
+OO.ui.MenuSelectWidget.prototype.updateItemVisibility = function () {
+ var i, item,
+ len = this.items.length,
+ showAll = !this.isVisible(),
+ filter = showAll ? null : this.getItemMatcher( this.$input.val() );
+
+ for ( i = 0; i < len; i++ ) {
+ item = this.items[ i ];
+ if ( item instanceof OO.ui.OptionWidget ) {
+ item.toggle( showAll || filter( item ) );
+ }
+ }
+
+ // Reevaluate clipping
+ this.clip();
+};
+
+/**
* @inheritdoc
*/
OO.ui.MenuSelectWidget.prototype.bindKeyDownListener = function () {
if ( this.$input ) {
this.$input.on( 'keydown', this.onKeyDownHandler );
} else {
- OO.ui.MenuSelectWidget.super.prototype.bindKeyDownListener.call( this );
+ OO.ui.MenuSelectWidget.parent.prototype.bindKeyDownListener.call( this );
}
};
@@ -15763,7 +18869,34 @@ OO.ui.MenuSelectWidget.prototype.unbindKeyDownListener = function () {
if ( this.$input ) {
this.$input.off( 'keydown', this.onKeyDownHandler );
} else {
- OO.ui.MenuSelectWidget.super.prototype.unbindKeyDownListener.call( this );
+ OO.ui.MenuSelectWidget.parent.prototype.unbindKeyDownListener.call( this );
+ }
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.MenuSelectWidget.prototype.bindKeyPressListener = function () {
+ if ( this.$input ) {
+ if ( this.filterFromInput ) {
+ this.$input.on( 'keydown mouseup cut paste change input select', this.onInputEditHandler );
+ }
+ } else {
+ OO.ui.MenuSelectWidget.parent.prototype.bindKeyPressListener.call( this );
+ }
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.MenuSelectWidget.prototype.unbindKeyPressListener = function () {
+ if ( this.$input ) {
+ if ( this.filterFromInput ) {
+ this.$input.off( 'keydown mouseup cut paste change input select', this.onInputEditHandler );
+ this.updateItemVisibility();
+ }
+ } else {
+ OO.ui.MenuSelectWidget.parent.prototype.unbindKeyPressListener.call( this );
}
};
@@ -15778,7 +18911,7 @@ OO.ui.MenuSelectWidget.prototype.unbindKeyDownListener = function () {
* @chainable
*/
OO.ui.MenuSelectWidget.prototype.chooseItem = function ( item ) {
- OO.ui.MenuSelectWidget.super.prototype.chooseItem.call( this, item );
+ OO.ui.MenuSelectWidget.parent.prototype.chooseItem.call( this, item );
this.toggle( false );
return this;
};
@@ -15790,7 +18923,7 @@ OO.ui.MenuSelectWidget.prototype.addItems = function ( items, index ) {
var i, len, item;
// Parent method
- OO.ui.MenuSelectWidget.super.prototype.addItems.call( this, items, index );
+ OO.ui.MenuSelectWidget.parent.prototype.addItems.call( this, items, index );
// Auto-initialize
if ( !this.newItems ) {
@@ -15818,7 +18951,7 @@ OO.ui.MenuSelectWidget.prototype.addItems = function ( items, index ) {
*/
OO.ui.MenuSelectWidget.prototype.removeItems = function ( items ) {
// Parent method
- OO.ui.MenuSelectWidget.super.prototype.removeItems.call( this, items );
+ OO.ui.MenuSelectWidget.parent.prototype.removeItems.call( this, items );
// Reevaluate clipping
this.clip();
@@ -15831,7 +18964,7 @@ OO.ui.MenuSelectWidget.prototype.removeItems = function ( items ) {
*/
OO.ui.MenuSelectWidget.prototype.clearItems = function () {
// Parent method
- OO.ui.MenuSelectWidget.super.prototype.clearItems.call( this );
+ OO.ui.MenuSelectWidget.parent.prototype.clearItems.call( this );
// Reevaluate clipping
this.clip();
@@ -15843,17 +18976,18 @@ OO.ui.MenuSelectWidget.prototype.clearItems = function () {
* @inheritdoc
*/
OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
- visible = ( visible === undefined ? !this.visible : !!visible ) && !!this.items.length;
+ var i, len, change;
- var i, len,
- change = visible !== this.isVisible();
+ visible = ( visible === undefined ? !this.visible : !!visible ) && !!this.items.length;
+ change = visible !== this.isVisible();
// Parent method
- OO.ui.MenuSelectWidget.super.prototype.toggle.call( this, visible );
+ OO.ui.MenuSelectWidget.parent.prototype.toggle.call( this, visible );
if ( change ) {
if ( visible ) {
this.bindKeyDownListener();
+ this.bindKeyPressListener();
if ( this.newItems && this.newItems.length ) {
for ( i = 0, len = this.newItems.length; i < len; i++ ) {
@@ -15865,15 +18999,12 @@ OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
// Auto-hide
if ( this.autoHide ) {
- this.getElementDocument().addEventListener(
- 'mousedown', this.onDocumentMouseDownHandler, true
- );
+ OO.ui.addCaptureEventListener( this.getElementDocument(), 'mousedown', this.onDocumentMouseDownHandler );
}
} else {
this.unbindKeyDownListener();
- this.getElementDocument().removeEventListener(
- 'mousedown', this.onDocumentMouseDownHandler, true
- );
+ this.unbindKeyPressListener();
+ OO.ui.removeCaptureEventListener( this.getElementDocument(), 'mousedown', this.onDocumentMouseDownHandler );
this.toggleClipping( false );
}
}
@@ -15882,21 +19013,28 @@ OO.ui.MenuSelectWidget.prototype.toggle = function ( visible ) {
};
/**
- * 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.
+ * FloatingMenuSelectWidget is a menu that will stick under a specified
+ * container, even when it is inserted elsewhere in the document (for example,
+ * in a OO.ui.Window's $overlay). This is sometimes necessary to prevent the
+ * menu from being clipped too aggresively.
+ *
+ * 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.MenuSelectWidget
+ * @mixins OO.ui.mixin.FloatableElement
*
* @constructor
- * @param {OO.ui.TextInputWidget} inputWidget Text input widget to provide menu for
+ * @param {OO.ui.Widget} [inputWidget] Widget to provide the menu for.
+ * Deprecated, omit this parameter and specify `$container` instead.
* @param {Object} [config] Configuration options
- * @cfg {jQuery} [$container=input.$element] Element to render menu under
+ * @cfg {jQuery} [$container=inputWidget.$element] Element to render menu under
*/
-OO.ui.TextInputMenuSelectWidget = function OoUiTextInputMenuSelectWidget( inputWidget, config ) {
- // Allow passing positional parameters inside the config object
+OO.ui.FloatingMenuSelectWidget = function OoUiFloatingMenuSelectWidget( inputWidget, config ) {
+ // Allow 'inputWidget' parameter and config for backwards compatibility
if ( OO.isPlainObject( inputWidget ) && config === undefined ) {
config = inputWidget;
inputWidget = config.inputWidget;
@@ -15906,104 +19044,74 @@ OO.ui.TextInputMenuSelectWidget = function OoUiTextInputMenuSelectWidget( inputW
config = config || {};
// Parent constructor
- OO.ui.TextInputMenuSelectWidget.super.call( this, config );
+ OO.ui.FloatingMenuSelectWidget.parent.call( this, config );
- // Properties
- this.inputWidget = inputWidget;
+ // Properties (must be set before mixin constructors)
+ this.inputWidget = inputWidget; // For backwards compatibility
this.$container = config.$container || this.inputWidget.$element;
- this.onWindowResizeHandler = this.onWindowResize.bind( this );
+
+ // Mixins constructors
+ OO.ui.mixin.FloatableElement.call( this, $.extend( {}, config, { $floatableContainer: this.$container } ) );
// Initialization
+ this.$element.addClass( 'oo-ui-floatingMenuSelectWidget' );
+ // For backwards compatibility
this.$element.addClass( 'oo-ui-textInputMenuSelectWidget' );
};
/* Setup */
-OO.inheritClass( OO.ui.TextInputMenuSelectWidget, OO.ui.MenuSelectWidget );
+OO.inheritClass( OO.ui.FloatingMenuSelectWidget, OO.ui.MenuSelectWidget );
+OO.mixinClass( OO.ui.FloatingMenuSelectWidget, OO.ui.mixin.FloatableElement );
-/* Methods */
+// For backwards compatibility
+OO.ui.TextInputMenuSelectWidget = OO.ui.FloatingMenuSelectWidget;
-/**
- * Handle window resize event.
- *
- * @private
- * @param {jQuery.Event} e Window resize event
- */
-OO.ui.TextInputMenuSelectWidget.prototype.onWindowResize = function () {
- this.position();
-};
+/* Methods */
/**
* @inheritdoc
*/
-OO.ui.TextInputMenuSelectWidget.prototype.toggle = function ( visible ) {
+OO.ui.FloatingMenuSelectWidget.prototype.toggle = function ( visible ) {
+ var change;
visible = visible === undefined ? !this.isVisible() : !!visible;
-
- var change = visible !== this.isVisible();
+ change = visible !== this.isVisible();
if ( change && visible ) {
// Make sure the width is set before the parent method runs.
- // After this we have to call this.position(); again to actually
- // position ourselves correctly.
- this.position();
+ this.setIdealSize( this.$container.width() );
}
// Parent method
- OO.ui.TextInputMenuSelectWidget.super.prototype.toggle.call( this, visible );
+ // This will call this.clip(), which is nonsensical since we're not positioned yet...
+ OO.ui.FloatingMenuSelectWidget.parent.prototype.toggle.call( this, visible );
if ( change ) {
- if ( this.isVisible() ) {
- this.position();
- $( this.getElementWindow() ).on( 'resize', this.onWindowResizeHandler );
- } else {
- $( this.getElementWindow() ).off( 'resize', this.onWindowResizeHandler );
- }
+ this.togglePositioning( this.isVisible() );
}
return this;
};
/**
- * Position the menu.
- *
- * @private
- * @chainable
- */
-OO.ui.TextInputMenuSelectWidget.prototype.position = function () {
- var $container = this.$container,
- pos = OO.ui.Element.static.getRelativePosition( $container, this.$element.offsetParent() );
-
- // Position under input
- pos.top += $container.height();
- this.$element.css( pos );
-
- // Set width
- this.setIdealSize( $container.width() );
- // We updated the position, so re-evaluate the clipping state
- this.clip();
-
- return this;
-};
-
-/**
* 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.
*
- * ####Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.####
+ * **Currently, this class is only used by {@link OO.ui.BookletLayout booklet layouts}.**
*
* @class
* @extends OO.ui.SelectWidget
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
OO.ui.OutlineSelectWidget = function OoUiOutlineSelectWidget( config ) {
// Parent constructor
- OO.ui.OutlineSelectWidget.super.call( this, config );
+ OO.ui.OutlineSelectWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.TabIndexedElement.call( this, config );
+ OO.ui.mixin.TabIndexedElement.call( this, config );
// Events
this.$element.on( {
@@ -16018,26 +19126,26 @@ OO.ui.OutlineSelectWidget = function OoUiOutlineSelectWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.OutlineSelectWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.OutlineSelectWidget, OO.ui.TabIndexedElement );
+OO.mixinClass( OO.ui.OutlineSelectWidget, OO.ui.mixin.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}.####
+ * **Currently, this class is only used by {@link OO.ui.IndexLayout index layouts}.**
*
* @class
* @extends OO.ui.SelectWidget
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
*/
OO.ui.TabSelectWidget = function OoUiTabSelectWidget( config ) {
// Parent constructor
- OO.ui.TabSelectWidget.super.call( this, config );
+ OO.ui.TabSelectWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.TabIndexedElement.call( this, config );
+ OO.ui.mixin.TabIndexedElement.call( this, config );
// Events
this.$element.on( {
@@ -16052,7 +19160,364 @@ OO.ui.TabSelectWidget = function OoUiTabSelectWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.TabSelectWidget, OO.ui.SelectWidget );
-OO.mixinClass( OO.ui.TabSelectWidget, OO.ui.TabIndexedElement );
+OO.mixinClass( OO.ui.TabSelectWidget, OO.ui.mixin.TabIndexedElement );
+
+/**
+ * NumberInputWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value
+ * can be entered manually) and two {@link OO.ui.ButtonWidget button widgets}
+ * (to adjust the value in increments) to allow the user to enter a number.
+ *
+ * @example
+ * // Example: A NumberInputWidget.
+ * var numberInput = new OO.ui.NumberInputWidget( {
+ * label: 'NumberInputWidget',
+ * input: { value: 5, min: 1, max: 10 }
+ * } );
+ * $( 'body' ).append( numberInput.$element );
+ *
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {Object} [input] Configuration options to pass to the {@link OO.ui.TextInputWidget text input widget}.
+ * @cfg {Object} [minusButton] Configuration options to pass to the {@link OO.ui.ButtonWidget decrementing button widget}.
+ * @cfg {Object} [plusButton] Configuration options to pass to the {@link OO.ui.ButtonWidget incrementing button widget}.
+ * @cfg {boolean} [isInteger=false] Whether the field accepts only integer values.
+ * @cfg {number} [min=-Infinity] Minimum allowed value
+ * @cfg {number} [max=Infinity] Maximum allowed value
+ * @cfg {number} [step=1] Delta when using the buttons or up/down arrow keys
+ * @cfg {number|null} [pageStep] Delta when using the page-up/page-down keys. Defaults to 10 times #step.
+ */
+OO.ui.NumberInputWidget = function OoUiNumberInputWidget( config ) {
+ // Configuration initialization
+ config = $.extend( {
+ isInteger: false,
+ min: -Infinity,
+ max: Infinity,
+ step: 1,
+ pageStep: null
+ }, config );
+
+ // Parent constructor
+ OO.ui.NumberInputWidget.parent.call( this, config );
+
+ // Properties
+ this.input = new OO.ui.TextInputWidget( $.extend(
+ {
+ disabled: this.isDisabled()
+ },
+ config.input
+ ) );
+ this.minusButton = new OO.ui.ButtonWidget( $.extend(
+ {
+ disabled: this.isDisabled(),
+ tabIndex: -1
+ },
+ config.minusButton,
+ {
+ classes: [ 'oo-ui-numberInputWidget-minusButton' ],
+ label: '−'
+ }
+ ) );
+ this.plusButton = new OO.ui.ButtonWidget( $.extend(
+ {
+ disabled: this.isDisabled(),
+ tabIndex: -1
+ },
+ config.plusButton,
+ {
+ classes: [ 'oo-ui-numberInputWidget-plusButton' ],
+ label: '+'
+ }
+ ) );
+
+ // Events
+ this.input.connect( this, {
+ change: this.emit.bind( this, 'change' ),
+ enter: this.emit.bind( this, 'enter' )
+ } );
+ this.input.$input.on( {
+ keydown: this.onKeyDown.bind( this ),
+ 'wheel mousewheel DOMMouseScroll': this.onWheel.bind( this )
+ } );
+ this.plusButton.connect( this, {
+ click: [ 'onButtonClick', +1 ]
+ } );
+ this.minusButton.connect( this, {
+ click: [ 'onButtonClick', -1 ]
+ } );
+
+ // Initialization
+ this.setIsInteger( !!config.isInteger );
+ this.setRange( config.min, config.max );
+ this.setStep( config.step, config.pageStep );
+
+ this.$field = $( '<div>' ).addClass( 'oo-ui-numberInputWidget-field' )
+ .append(
+ this.minusButton.$element,
+ this.input.$element,
+ this.plusButton.$element
+ );
+ this.$element.addClass( 'oo-ui-numberInputWidget' ).append( this.$field );
+ this.input.setValidation( this.validateNumber.bind( this ) );
+};
+
+/* Setup */
+
+OO.inheritClass( OO.ui.NumberInputWidget, OO.ui.Widget );
+
+/* Events */
+
+/**
+ * A `change` event is emitted when the value of the input changes.
+ *
+ * @event change
+ */
+
+/**
+ * An `enter` event is emitted when the user presses 'enter' inside the text box.
+ *
+ * @event enter
+ */
+
+/* Methods */
+
+/**
+ * Set whether only integers are allowed
+ * @param {boolean} flag
+ */
+OO.ui.NumberInputWidget.prototype.setIsInteger = function ( flag ) {
+ this.isInteger = !!flag;
+ this.input.setValidityFlag();
+};
+
+/**
+ * Get whether only integers are allowed
+ * @return {boolean} Flag value
+ */
+OO.ui.NumberInputWidget.prototype.getIsInteger = function () {
+ return this.isInteger;
+};
+
+/**
+ * Set the range of allowed values
+ * @param {number} min Minimum allowed value
+ * @param {number} max Maximum allowed value
+ */
+OO.ui.NumberInputWidget.prototype.setRange = function ( min, max ) {
+ if ( min > max ) {
+ throw new Error( 'Minimum (' + min + ') must not be greater than maximum (' + max + ')' );
+ }
+ this.min = min;
+ this.max = max;
+ this.input.setValidityFlag();
+};
+
+/**
+ * Get the current range
+ * @return {number[]} Minimum and maximum values
+ */
+OO.ui.NumberInputWidget.prototype.getRange = function () {
+ return [ this.min, this.max ];
+};
+
+/**
+ * Set the stepping deltas
+ * @param {number} step Normal step
+ * @param {number|null} pageStep Page step. If null, 10 * step will be used.
+ */
+OO.ui.NumberInputWidget.prototype.setStep = function ( step, pageStep ) {
+ if ( step <= 0 ) {
+ throw new Error( 'Step value must be positive' );
+ }
+ if ( pageStep === null ) {
+ pageStep = step * 10;
+ } else if ( pageStep <= 0 ) {
+ throw new Error( 'Page step value must be positive' );
+ }
+ this.step = step;
+ this.pageStep = pageStep;
+};
+
+/**
+ * Get the current stepping values
+ * @return {number[]} Step and page step
+ */
+OO.ui.NumberInputWidget.prototype.getStep = function () {
+ return [ this.step, this.pageStep ];
+};
+
+/**
+ * Get the current value of the widget
+ * @return {string}
+ */
+OO.ui.NumberInputWidget.prototype.getValue = function () {
+ return this.input.getValue();
+};
+
+/**
+ * Get the current value of the widget as a number
+ * @return {number} May be NaN, or an invalid number
+ */
+OO.ui.NumberInputWidget.prototype.getNumericValue = function () {
+ return +this.input.getValue();
+};
+
+/**
+ * Set the value of the widget
+ * @param {string} value Invalid values are allowed
+ */
+OO.ui.NumberInputWidget.prototype.setValue = function ( value ) {
+ this.input.setValue( value );
+};
+
+/**
+ * Adjust the value of the widget
+ * @param {number} delta Adjustment amount
+ */
+OO.ui.NumberInputWidget.prototype.adjustValue = function ( delta ) {
+ var n, v = this.getNumericValue();
+
+ delta = +delta;
+ if ( isNaN( delta ) || !isFinite( delta ) ) {
+ throw new Error( 'Delta must be a finite number' );
+ }
+
+ if ( isNaN( v ) ) {
+ n = 0;
+ } else {
+ n = v + delta;
+ n = Math.max( Math.min( n, this.max ), this.min );
+ if ( this.isInteger ) {
+ n = Math.round( n );
+ }
+ }
+
+ if ( n !== v ) {
+ this.setValue( n );
+ }
+};
+
+/**
+ * Validate input
+ * @private
+ * @param {string} value Field value
+ * @return {boolean}
+ */
+OO.ui.NumberInputWidget.prototype.validateNumber = function ( value ) {
+ var n = +value;
+ if ( isNaN( n ) || !isFinite( n ) ) {
+ return false;
+ }
+
+ /*jshint bitwise: false */
+ if ( this.isInteger && ( n | 0 ) !== n ) {
+ return false;
+ }
+ /*jshint bitwise: true */
+
+ if ( n < this.min || n > this.max ) {
+ return false;
+ }
+
+ return true;
+};
+
+/**
+ * Handle mouse click events.
+ *
+ * @private
+ * @param {number} dir +1 or -1
+ */
+OO.ui.NumberInputWidget.prototype.onButtonClick = function ( dir ) {
+ this.adjustValue( dir * this.step );
+};
+
+/**
+ * Handle mouse wheel events.
+ *
+ * @private
+ * @param {jQuery.Event} event
+ */
+OO.ui.NumberInputWidget.prototype.onWheel = function ( event ) {
+ var delta = 0;
+
+ // Standard 'wheel' event
+ if ( event.originalEvent.deltaMode !== undefined ) {
+ this.sawWheelEvent = true;
+ }
+ if ( event.originalEvent.deltaY ) {
+ delta = -event.originalEvent.deltaY;
+ } else if ( event.originalEvent.deltaX ) {
+ delta = event.originalEvent.deltaX;
+ }
+
+ // Non-standard events
+ if ( !this.sawWheelEvent ) {
+ if ( event.originalEvent.wheelDeltaX ) {
+ delta = -event.originalEvent.wheelDeltaX;
+ } else if ( event.originalEvent.wheelDeltaY ) {
+ delta = event.originalEvent.wheelDeltaY;
+ } else if ( event.originalEvent.wheelDelta ) {
+ delta = event.originalEvent.wheelDelta;
+ } else if ( event.originalEvent.detail ) {
+ delta = -event.originalEvent.detail;
+ }
+ }
+
+ if ( delta ) {
+ delta = delta < 0 ? -1 : 1;
+ this.adjustValue( delta * this.step );
+ }
+
+ return false;
+};
+
+/**
+ * Handle key down events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key down event
+ */
+OO.ui.NumberInputWidget.prototype.onKeyDown = function ( e ) {
+ if ( !this.isDisabled() ) {
+ switch ( e.which ) {
+ case OO.ui.Keys.UP:
+ this.adjustValue( this.step );
+ return false;
+ case OO.ui.Keys.DOWN:
+ this.adjustValue( -this.step );
+ return false;
+ case OO.ui.Keys.PAGEUP:
+ this.adjustValue( this.pageStep );
+ return false;
+ case OO.ui.Keys.PAGEDOWN:
+ this.adjustValue( -this.pageStep );
+ return false;
+ }
+ }
+};
+
+/**
+ * @inheritdoc
+ */
+OO.ui.NumberInputWidget.prototype.setDisabled = function ( disabled ) {
+ // Parent method
+ OO.ui.NumberInputWidget.parent.prototype.setDisabled.call( this, disabled );
+
+ if ( this.input ) {
+ this.input.setDisabled( this.isDisabled() );
+ }
+ if ( this.minusButton ) {
+ this.minusButton.setDisabled( this.isDisabled() );
+ }
+ if ( this.plusButton ) {
+ this.plusButton.setDisabled( this.isDisabled() );
+ }
+
+ return this;
+};
/**
* ToggleSwitches are switches that slide on and off. Their state is represented by a Boolean
@@ -16078,7 +19543,7 @@ OO.mixinClass( OO.ui.TabSelectWidget, OO.ui.TabIndexedElement );
*
* @class
* @extends OO.ui.ToggleWidget
- * @mixins OO.ui.TabIndexedElement
+ * @mixins OO.ui.mixin.TabIndexedElement
*
* @constructor
* @param {Object} [config] Configuration options
@@ -16087,10 +19552,10 @@ OO.mixinClass( OO.ui.TabSelectWidget, OO.ui.TabIndexedElement );
*/
OO.ui.ToggleSwitchWidget = function OoUiToggleSwitchWidget( config ) {
// Parent constructor
- OO.ui.ToggleSwitchWidget.super.call( this, config );
+ OO.ui.ToggleSwitchWidget.parent.call( this, config );
// Mixin constructors
- OO.ui.TabIndexedElement.call( this, config );
+ OO.ui.mixin.TabIndexedElement.call( this, config );
// Properties
this.dragging = false;
@@ -16117,7 +19582,7 @@ OO.ui.ToggleSwitchWidget = function OoUiToggleSwitchWidget( config ) {
/* Setup */
OO.inheritClass( OO.ui.ToggleSwitchWidget, OO.ui.ToggleWidget );
-OO.mixinClass( OO.ui.ToggleSwitchWidget, OO.ui.TabIndexedElement );
+OO.mixinClass( OO.ui.ToggleSwitchWidget, OO.ui.mixin.TabIndexedElement );
/* Methods */
@@ -16147,4 +19612,104 @@ OO.ui.ToggleSwitchWidget.prototype.onKeyPress = function ( e ) {
}
};
+/*!
+ * Deprecated aliases for classes in the `OO.ui.mixin` namespace.
+ */
+
+/**
+ * @inheritdoc OO.ui.mixin.ButtonElement
+ * @deprecated Use {@link OO.ui.mixin.ButtonElement} instead.
+ */
+OO.ui.ButtonElement = OO.ui.mixin.ButtonElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.ClippableElement
+ * @deprecated Use {@link OO.ui.mixin.ClippableElement} instead.
+ */
+OO.ui.ClippableElement = OO.ui.mixin.ClippableElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.DraggableElement
+ * @deprecated Use {@link OO.ui.mixin.DraggableElement} instead.
+ */
+OO.ui.DraggableElement = OO.ui.mixin.DraggableElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.DraggableGroupElement
+ * @deprecated Use {@link OO.ui.mixin.DraggableGroupElement} instead.
+ */
+OO.ui.DraggableGroupElement = OO.ui.mixin.DraggableGroupElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.FlaggedElement
+ * @deprecated Use {@link OO.ui.mixin.FlaggedElement} instead.
+ */
+OO.ui.FlaggedElement = OO.ui.mixin.FlaggedElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.GroupElement
+ * @deprecated Use {@link OO.ui.mixin.GroupElement} instead.
+ */
+OO.ui.GroupElement = OO.ui.mixin.GroupElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.GroupWidget
+ * @deprecated Use {@link OO.ui.mixin.GroupWidget} instead.
+ */
+OO.ui.GroupWidget = OO.ui.mixin.GroupWidget;
+
+/**
+ * @inheritdoc OO.ui.mixin.IconElement
+ * @deprecated Use {@link OO.ui.mixin.IconElement} instead.
+ */
+OO.ui.IconElement = OO.ui.mixin.IconElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.IndicatorElement
+ * @deprecated Use {@link OO.ui.mixin.IndicatorElement} instead.
+ */
+OO.ui.IndicatorElement = OO.ui.mixin.IndicatorElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.ItemWidget
+ * @deprecated Use {@link OO.ui.mixin.ItemWidget} instead.
+ */
+OO.ui.ItemWidget = OO.ui.mixin.ItemWidget;
+
+/**
+ * @inheritdoc OO.ui.mixin.LabelElement
+ * @deprecated Use {@link OO.ui.mixin.LabelElement} instead.
+ */
+OO.ui.LabelElement = OO.ui.mixin.LabelElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.LookupElement
+ * @deprecated Use {@link OO.ui.mixin.LookupElement} instead.
+ */
+OO.ui.LookupElement = OO.ui.mixin.LookupElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.PendingElement
+ * @deprecated Use {@link OO.ui.mixin.PendingElement} instead.
+ */
+OO.ui.PendingElement = OO.ui.mixin.PendingElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.PopupElement
+ * @deprecated Use {@link OO.ui.mixin.PopupElement} instead.
+ */
+OO.ui.PopupElement = OO.ui.mixin.PopupElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.TabIndexedElement
+ * @deprecated Use {@link OO.ui.mixin.TabIndexedElement} instead.
+ */
+OO.ui.TabIndexedElement = OO.ui.mixin.TabIndexedElement;
+
+/**
+ * @inheritdoc OO.ui.mixin.TitledElement
+ * @deprecated Use {@link OO.ui.mixin.TitledElement} instead.
+ */
+OO.ui.TitledElement = OO.ui.mixin.TitledElement;
+
}( OO ) );
diff --git a/resources/lib/oojs-ui/themes/apex/icons-editing-advanced.json b/resources/lib/oojs-ui/themes/apex/icons-editing-advanced.json
new file mode 100644
index 00000000..f7b38628
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/icons-editing-advanced.json
@@ -0,0 +1,79 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "alignCentre": { "file": "images/icons/align-center.svg" },
+ "alignLeft": { "file": "images/icons/align-float-left.svg" },
+ "alignRight": { "file": "images/icons/align-float-right.svg" },
+ "calendar": { "file": {
+ "ltr": "images/icons/calendar-ltr.svg",
+ "rtl": "images/icons/calendar-rtl.svg"
+ } },
+ "find": { "file": {
+ "ltr": "images/icons/find-ltr.svg",
+ "rtl": "images/icons/find-rtl.svg"
+ } },
+ "insert": { "file": "images/icons/insert.svg" },
+ "layout": { "file": {
+ "ltr": "images/icons/layout-ltr.svg",
+ "rtl": "images/icons/layout-rtl.svg"
+ } },
+ "newline": { "file": {
+ "ltr": "images/icons/newline-ltr.svg",
+ "rtl": "images/icons/newline-rtl.svg"
+ } },
+ "redirect": { "file": {
+ "ltr": "images/icons/redirect-ltr.svg",
+ "rtl": "images/icons/redirect-rtl.svg"
+ } },
+ "noWikiText": { "file": {
+ "ltr": "images/icons/noWikiText-ltr.svg",
+ "rtl": "images/icons/noWikiText-rtl.svg"
+ } },
+ "outline": { "file": {
+ "ltr": "images/icons/outline-ltr.svg",
+ "rtl": "images/icons/outline-rtl.svg"
+ } },
+ "puzzle": { "file": {
+ "ltr": "images/icons/puzzle-ltr.svg",
+ "rtl": "images/icons/puzzle-rtl.svg"
+ } },
+ "quotes": { "file": {
+ "ltr": "images/icons/quotes-ltr.svg",
+ "rtl": "images/icons/quotes-rtl.svg"
+ } },
+ "quotesAdd": { "file": {
+ "ltr": "images/icons/quotesAdd-ltr.svg",
+ "rtl": "images/icons/quotesAdd-rtl.svg"
+ } },
+ "redirect": { "file": {
+ "ltr": "images/icons/redirect-ltr.svg",
+ "rtl": "images/icons/redirect-rtl.svg"
+ } },
+ "searchCaseSensitive": { "file": "images/icons/case-sensitive.svg" },
+ "searchRegularExpression": { "file": "images/icons/regular-expression.svg" },
+ "specialCharacter": { "file": "images/icons/specialCharacter.svg" },
+ "table": { "file": "images/icons/table.svg" },
+ "tableAddColumnAfter": { "file": {
+ "ltr": "images/icons/table-insert-column-rtl.svg",
+ "rtl": "images/icons/table-insert-column-ltr.svg"
+ } },
+ "tableAddColumnBefore": { "file": {
+ "ltr": "images/icons/table-insert-column-ltr.svg",
+ "rtl": "images/icons/table-insert-column-rtl.svg"
+ } },
+ "tableAddRowAfter": { "file": "images/icons/table-insert-row-after.svg" },
+ "tableAddRowBefore": { "file": "images/icons/table-insert-row-before.svg" },
+ "tableCaption": { "file": "images/icons/table-caption.svg" },
+ "tableMergeCells": { "file": "images/icons/table-merge-cells.svg" },
+ "templateAdd": { "file": {
+ "ltr": "images/icons/templateAdd-ltr.svg",
+ "rtl": "images/icons/templateAdd-rtl.svg"
+ } },
+ "translation": { "file": {
+ "ltr": "images/icons/translation-ltr.svg",
+ "rtl": "images/icons/translation-rtl.svg"
+ } },
+ "wikiText": { "file": "images/icons/wikiText.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/apex/icons-editing-core.json b/resources/lib/oojs-ui/themes/apex/icons-editing-core.json
new file mode 100644
index 00000000..ceb31992
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/icons-editing-core.json
@@ -0,0 +1,24 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "edit": { "file": {
+ "ltr": "images/icons/edit-ltr.svg",
+ "rtl": "images/icons/edit-rtl.svg"
+ } },
+ "editLock": { "file": {
+ "ltr": "images/icons/editLock-ltr.svg",
+ "rtl": "images/icons/editLock-rtl.svg"
+ } },
+ "editUndo": { "file": {
+ "ltr": "images/icons/editUndo-ltr.svg",
+ "rtl": "images/icons/editUndo-rtl.svg"
+ } },
+ "link": { "file": "images/icons/link.svg" },
+ "linkExternal": { "file": {
+ "ltr": "images/icons/external-link-ltr.svg",
+ "rtl": "images/icons/external-link-rtl.svg"
+ } },
+ "linkSecure": { "file": "images/icons/secure-link.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/apex/icons-editing-list.json b/resources/lib/oojs-ui/themes/apex/icons-editing-list.json
new file mode 100644
index 00000000..490f8faf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/icons-editing-list.json
@@ -0,0 +1,22 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "indent": { "file": {
+ "ltr": "images/icons/indent-ltr.svg",
+ "rtl": "images/icons/indent-rtl.svg"
+ } },
+ "listBullet": { "file": {
+ "ltr": "images/icons/listBullet-ltr.svg",
+ "rtl": "images/icons/listBullet-rtl.svg"
+ } },
+ "listNumbered": { "file": {
+ "ltr": "images/icons/listNumbered-ltr.svg",
+ "rtl": "images/icons/listNumbered-rtl.svg"
+ } },
+ "outdent": { "file": {
+ "ltr": "images/icons/outdent-ltr.svg",
+ "rtl": "images/icons/outdent-rtl.svg"
+ } }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/apex/icons-editing-styling.json b/resources/lib/oojs-ui/themes/apex/icons-editing-styling.json
new file mode 100644
index 00000000..4fb736c5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/icons-editing-styling.json
@@ -0,0 +1,72 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "bigger": { "file": {
+ "ltr": "images/icons/bigger-ltr.svg",
+ "rtl": "images/icons/bigger-rtl.svg"
+ } },
+ "smaller": { "file": {
+ "ltr": "images/icons/smaller-ltr.svg",
+ "rtl": "images/icons/smaller-rtl.svg"
+ } },
+ "subscript": { "file": {
+ "ltr": "images/icons/subscript-ltr.svg",
+ "rtl": "images/icons/subscript-rtl.svg"
+ } },
+ "superscript": { "file": {
+ "ltr": "images/icons/superscript-ltr.svg",
+ "rtl": "images/icons/superscript-rtl.svg"
+ } },
+ "bold": { "file": {
+ "default": "images/icons/bold-a.svg",
+ "lang": {
+ "ar": "images/icons/bold-arab-ain.svg",
+ "be": "images/icons/bold-cyrl-te.svg",
+ "cs,en,he,ml,pl,sco": "images/icons/bold-b.svg",
+ "da,de,hu,ksh,nn,no,sv": "images/icons/bold-f.svg",
+ "es,gl,pt": "images/icons/bold-n.svg",
+ "eu,fi": "images/icons/bold-l.svg",
+ "fa": "images/icons/bold-arab-dad.svg",
+ "fr,it": "images/icons/bold-g.svg",
+ "hy": "images/icons/bold-armn-to.svg",
+ "ka": "images/icons/bold-geor-man.svg",
+ "ky,ru": "images/icons/bold-cyrl-zhe.svg",
+ "nl": "images/icons/bold-v.svg",
+ "os": "images/icons/bold-cyrl-be.svg"
+ }
+ } },
+ "italic": { "file": {
+ "default": "images/icons/italic-a.svg",
+ "lang": {
+ "ar": "images/icons/italic-arab-meem.svg",
+ "cs,en,fr,he,ml,pl,pt,sco": "images/icons/italic-i.svg",
+ "be,da,de,fi,ky,nn,no,os,sv,ru": "images/icons/italic-k.svg",
+ "es,gl,it,nl": "images/icons/italic-c.svg",
+ "eu": "images/icons/italic-e.svg",
+ "fa": "images/icons/italic-arab-keheh-jeem.svg",
+ "hu": "images/icons/italic-d.svg",
+ "hy": "images/icons/italic-armn-sha.svg",
+ "ksh": "images/icons/italic-s.svg",
+ "ka": "images/icons/italic-geor-kan.svg"
+ }
+ } },
+ "strikethrough": { "file": {
+ "default": "images/icons/strikethrough-a.svg",
+ "lang": {
+ "en": "images/icons/strikethrough-s.svg",
+ "fi": "images/icons/strikethrough-y.svg"
+ }
+ } },
+ "underline": { "file": {
+ "default": "images/icons/underline-a.svg",
+ "lang": {
+ "en": "images/icons/underline-u.svg"
+ }
+ } },
+ "textLanguage": { "file": "images/icons/language.svg" },
+ "textDirLTR": { "file": "images/icons/text-dir-lefttoright.svg" },
+ "textDirRTL": { "file": "images/icons/text-dir-righttoleft.svg" },
+ "textStyle": { "file": "images/icons/text-style.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/apex/icons-moderation.json b/resources/lib/oojs-ui/themes/apex/icons-moderation.json
new file mode 100644
index 00000000..f904cc26
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/icons-moderation.json
@@ -0,0 +1,33 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "block": { "file": "images/icons/block.svg" },
+ "blockUndo": { "file": {
+ "ltr": "images/icons/blockUndo-ltr.svg",
+ "rtl": "images/icons/blockUndo-rtl.svg"
+ } },
+ "flag": { "file": {
+ "ltr": "images/icons/flag-ltr.svg",
+ "rtl": "images/icons/flag-rtl.svg"
+ } },
+ "flagUndo": { "file": {
+ "ltr": "images/icons/flagUndo-ltr.svg",
+ "rtl": "images/icons/flagUndo-rtl.svg"
+ } },
+ "lock": { "file": "images/icons/lock.svg" },
+ "star": { "file": "images/icons/star.svg" },
+ "trash": { "file": "images/icons/trash.svg" },
+ "trashUndo": { "file": {
+ "ltr": "images/icons/trashUndo-ltr.svg",
+ "rtl": "images/icons/trashUndo-rtl.svg"
+ } },
+ "unLock": { "file": {
+ "ltr": "images/icons/unLock-ltr.svg",
+ "rtl": "images/icons/unLock-rtl.svg"
+ } },
+ "unStar": { "file": "images/icons/unStar.svg" }
+
+
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/apex/icons-movement.json b/resources/lib/oojs-ui/themes/apex/icons-movement.json
new file mode 100644
index 00000000..9aa1b809
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/icons-movement.json
@@ -0,0 +1,27 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "arrowNext": { "file": {
+ "ltr": "images/icons/arrow-ltr.svg",
+ "rtl": "images/icons/arrow-rtl.svg"
+ } },
+ "arrowLast": { "file": {
+ "ltr": "images/icons/arrow-rtl.svg",
+ "rtl": "images/icons/arrow-ltr.svg"
+ } },
+ "caretNext": { "file": {
+ "ltr": "images/icons/caret-rtl.svg",
+ "rtl": "images/icons/caret-ltr.svg"
+ } },
+ "caretLast": { "file": {
+ "ltr": "images/icons/caret-ltr.svg",
+ "rtl": "images/icons/caret-rtl.svg"
+ } },
+ "caretDown": { "file": "images/icons/caretDown.svg" },
+ "caretUp": { "file": "images/icons/caretUp.svg" },
+ "downTriangle": { "file": "images/icons/downTriangle.svg" },
+ "move": { "file": "images/icons/move.svg" },
+ "upTriangle": { "file": "images/icons/upTriangle.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/apex/icons.json b/resources/lib/oojs-ui/themes/apex/icons.json
new file mode 100644
index 00000000..92791d66
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/icons.json
@@ -0,0 +1,51 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "add": { "file": "images/icons/add.svg" },
+ "advanced": { "file": "images/icons/advanced.svg" },
+ "alert": { "file": "images/icons/alert.svg" },
+ "cancel": { "file": "images/icons/cancel.svg" },
+ "check": { "file": "images/icons/check.svg" },
+ "circle": { "file": "images/icons/circle.svg" },
+ "close": { "file": "images/icons/close.svg" },
+ "code": { "file": "images/icons/code.svg" },
+ "collapse": { "file": "images/icons/collapse.svg" },
+ "comment": { "file": "images/icons/comment.svg" },
+ "ellipsis": { "file": "images/icons/ellipsis.svg" },
+ "expand": { "file": "images/icons/expand.svg" },
+ "help": { "file": {
+ "ltr": "images/icons/help-ltr.svg",
+ "rtl": "images/icons/help-rtl.svg",
+ "lang": {
+ "he,yi": "images/icons/help-ltr.svg"
+ }
+ } },
+ "history": { "file": "images/icons/history.svg" },
+ "info": { "file": "images/icons/info.svg" },
+ "menu": { "file": "images/icons/menu.svg" },
+ "next": { "file": {
+ "ltr": "images/icons/move-ltr.svg",
+ "rtl": "images/icons/move-rtl.svg"
+ } },
+ "notice": { "file": "images/icons/notice.svg" },
+ "picture": { "file": "images/icons/picture.svg" },
+ "previous": { "file": {
+ "ltr": "images/icons/move-rtl.svg",
+ "rtl": "images/icons/move-ltr.svg"
+ } },
+ "redo": { "file": {
+ "ltr": "images/icons/arched-arrow-ltr.svg",
+ "rtl": "images/icons/arched-arrow-rtl.svg"
+ } },
+ "remove": { "file": "images/icons/remove.svg" },
+ "search": { "file": "images/icons/search.svg" },
+ "settings": { "file": "images/icons/settings.svg" },
+ "tag": { "file": "images/icons/tag.svg" },
+ "undo": { "file": {
+ "ltr": "images/icons/arched-arrow-rtl.svg",
+ "rtl": "images/icons/arched-arrow-ltr.svg"
+ } },
+ "window": { "file": "images/icons/window.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/add.png b/resources/lib/oojs-ui/themes/apex/images/icons/add.png
new file mode 100644
index 00000000..730d1029
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/add.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/add.svg b/resources/lib/oojs-ui/themes/apex/images/icons/add.svg
new file mode 100644
index 00000000..85e39feb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/add.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="add">
+ <path id="plus" d="M13 8h-2v3H8v2h3v3h2v-3h3v-2h-3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/advanced.png b/resources/lib/oojs-ui/themes/apex/images/icons/advanced.png
new file mode 100644
index 00000000..3709f21a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/advanced.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/advanced.svg b/resources/lib/oojs-ui/themes/apex/images/icons/advanced.svg
new file mode 100644
index 00000000..8d968767
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/advanced.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="settings">
+ <path id="gear" d="M20.87 13.476c.078-.482.13-.972.13-1.476s-.052-.994-.13-1.476l-2.464-.26c-.15-.555-.367-1.08-.648-1.57l1.558-1.923c-.576-.802-1.28-1.51-2.087-2.083L15.3 6.245c-.488-.28-1.015-.5-1.57-.648l-.26-2.463C12.996 3.054 12.506 3 12 3s-.994.052-1.476.13l-.26 2.464c-.554.15-1.08.367-1.57.648L6.772 4.685c-.804.576-1.51 1.28-2.085 2.086L6.245 8.7c-.28.488-.5 1.015-.648 1.57l-2.463.26c-.08.48-.132.97-.132 1.475s.052.995.13 1.477l2.464.26c.15.554.367 1.08.648 1.57l-1.558 1.92c.576.805 1.28 1.51 2.087 2.086l1.925-1.558c.488.28 1.015.5 1.57.648l.26 2.463c.48.075.97.13 1.475.13s.994-.055 1.476-.13l.26-2.467c.552-.15 1.08-.367 1.57-.648l1.92 1.558c.805-.576 1.51-1.28 2.086-2.087L17.758 15.3c.28-.487.5-1.014.647-1.57l2.463-.26zM12 15.998c-2.21 0-3.998-1.79-3.998-3.998S9.792 8.002 12 8.002s3.998 1.79 3.998 3.998-1.79 3.998-3.998 3.998z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/alert.png b/resources/lib/oojs-ui/themes/apex/images/icons/alert.png
new file mode 100644
index 00000000..98e94fbe
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/alert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/alert.svg b/resources/lib/oojs-ui/themes/apex/images/icons/alert.svg
new file mode 100644
index 00000000..8b601d5b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/alert.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="alert">
+ <path id="point" d="M11 16h2v2h-2z"/>
+ <path id="stroke" d="M13.516 10h-3L11 15h2z"/>
+ <path id="triangle" d="M12.017 5.974L19.537 19H4.497l7.52-13.026m0-2.474c-.545 0-1.09.357-1.5 1.07L2.53 18.403C1.705 19.833 2.38 21 4.03 21H20c1.65 0 2.325-1.17 1.5-2.6L13.517 4.575c-.413-.715-.956-1.072-1.5-1.072z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/align-center.png b/resources/lib/oojs-ui/themes/apex/images/icons/align-center.png
new file mode 100644
index 00000000..92d231e2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/align-center.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/align-center.svg b/resources/lib/oojs-ui/themes/apex/images/icons/align-center.svg
new file mode 100644
index 00000000..4697eb9f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 1H9c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zm-5.5 9h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0-12h17c.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/apex/images/icons/align-float-left.png b/resources/lib/oojs-ui/themes/apex/images/icons/align-float-left.png
new file mode 100644
index 00000000..2880478c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/align-float-left.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/align-float-left.svg b/resources/lib/oojs-ui/themes/apex/images/icons/align-float-left.svg
new file mode 100644
index 00000000..1c95377b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 1H4c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zm9.5 0h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0 3h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0 3h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm-10-9h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0 12h17c.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/apex/images/icons/align-float-right.png b/resources/lib/oojs-ui/themes/apex/images/icons/align-float-right.png
new file mode 100644
index 00000000..e9c2f0ea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/align-float-right.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/align-float-right.svg b/resources/lib/oojs-ui/themes/apex/images/icons/align-float-right.svg
new file mode 100644
index 00000000..2467f7f8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-1zm-9.5 0h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm0 3h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm0 3h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm10-9h-17c-.277 0-.5.223-.5.5s.223.5.5.5h17c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm0 12h-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/apex/images/icons/arched-arrow-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-ltr.png
new file mode 100644
index 00000000..114ce31c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-ltr.svg
new file mode 100644
index 00000000..1c2abb70
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/arched-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="arched-arrow-ltr">
+ <path id="arrow" d="M19.925 14.937l-2.39-6.9-1.48 2.328c-.965-.845-2.7-1.85-5.514-1.823-4.883.046-6.52 4.244-6.52 4.244s2.753-2.64 6.925-1.95c1.73.287 3.007 1.207 3.675 1.792l-1.475 2.32 6.782-.01z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-rtl.png
new file mode 100644
index 00000000..83a1c237
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/arched-arrow-rtl.svg
new file mode 100644
index 00000000..9a7dbe62
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/arched-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 id="arched-arrow-rtl">
+ <path id="arrow" d="M13.4 8.542c-2.813-.027-4.548.978-5.512 1.823l-1.48-2.33-2.39 6.902 6.78.01-1.473-2.32c.668-.584 1.945-1.504 3.675-1.79 4.172-.69 6.925 1.948 6.925 1.948S18.288 8.588 13.4 8.542z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/arrow-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/arrow-ltr.png
new file mode 100644
index 00000000..8bef0a51
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/arrow-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/arrow-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/arrow-ltr.svg
new file mode 100644
index 00000000..a0097cb4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 12H6c-1.7 0-3 1.3-3 3h13v3l5-4.5L16 9v3z" id="path6"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/arrow-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/arrow-rtl.png
new file mode 100644
index 00000000..26e3e69f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/arrow-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/arrow-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/arrow-rtl.svg
new file mode 100644
index 00000000..54d6d259
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 3H8v3l-5-4.5L8 9v3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bigger-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/bigger-ltr.png
new file mode 100644
index 00000000..b1c13a23
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bigger-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bigger-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bigger-ltr.svg
new file mode 100644
index 00000000..6d95fc66
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 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="M15.5 9h7L19 3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bigger-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/bigger-rtl.png
new file mode 100644
index 00000000..052ae37f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bigger-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bigger-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bigger-rtl.svg
new file mode 100644
index 00000000..807cdd91
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/block.png b/resources/lib/oojs-ui/themes/apex/images/icons/block.png
new file mode 100644
index 00000000..181daceb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/block.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/block.svg b/resources/lib/oojs-ui/themes/apex/images/icons/block.svg
new file mode 100644
index 00000000..6299c30e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 9H7v-2h10v2z" id="path4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-ltr.png
new file mode 100644
index 00000000..76e0db4b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-ltr.svg
new file mode 100644
index 00000000..f6d5486d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.4L13 11h4zM4 4L3 5l2.4 2.4C4.5 8.7 4 10.3 4 12c0 4.4 3.6 8 8 8 1.7 0 3.3-.5 4.6-1.4L19 21l1-1L4 4zm3 9v-2h2l2 2H7z" id="path68"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-rtl.png
new file mode 100644
index 00000000..e31809e5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/blockUndo-rtl.svg
new file mode 100644
index 00000000..d0ddde0e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.6C4.5 15.3 4 13.7 4 12c0-4.4 3.6-8 8-8 1.7 0 3.3.5 4.6 1.4L11 11H7zm13-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.4L5 21l-1-1L20 4zm-3 9v-2h-2l-2 2h4z" id="path68"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-a.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-a.png
new file mode 100644
index 00000000..86611e35
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-a.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-a.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-a.svg
new file mode 100644
index 00000000..d5cee050
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 18h3L14 6h-3L6 18h3l1.25-3h4.5L16 18zm-4.917-5L12.5 9.6l1.417 3.4h-2.834z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-ain.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-ain.png
new file mode 100644
index 00000000..e9dce687
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-ain.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-ain.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-ain.svg
new file mode 100644
index 00000000..23ed091a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.35 1.386 2.1 4.16 2.258l2.186-.03.318.045c-.03.123-.25.34-.66.65l-.09.064c-1.236.93-2.423 1.393-3.56 1.393-1.143 0-2.046-.33-2.71-.99-.65-.66-.976-1.56-.976-2.7.006-1.353.567-2.572 1.685-3.657v-.043l-.607-.55c-.15-.18-.222-.39-.222-.63 0-.49.24-1.11.718-1.863.65-1.046 1.303-1.566 1.958-1.56.886.004 1.618.42 2.194 1.245.324.48-.03.55-1.065.22-.842-.33-1.527-.05-2.054.826l.016.074 1.123.866.05.005c1.404-.496 2.418-.74 3.043-.724-.058.116-.14.36-.243.732-.105.357-.206.684-.305.982l-.126.373-.386.05c-1.743.24-2.992.716-3.745 1.43-.464.463-.698.972-.703 1.524"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-dad.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-dad.png
new file mode 100644
index 00000000..46d579b8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-dad.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-dad.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-arab-dad.svg
new file mode 100644
index 00000000..7e6769d9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.41 8.232l-1.675-.665L15.43 6l1.687.64-.707 1.592m.775 3.078c-.51-.286-1-.427-1.476-.423-.475 0-.986.205-1.536.616l-.506.38.006.024c1.084.066 1.934.1 2.55.1h.314c.57-.022.994-.065 1.278-.132-.067-.17-.275-.36-.625-.566h-.005M10.382 14.6c-.017-.904-.33-1.87-.938-2.898l1.294-1.73.118.15c.267.336.504.924.713 1.766l.065.05c.496-.007.942-.17 1.338-.484v-.006l1.732-1.53c.68-.6 1.282-.9 1.807-.9.384.003.85.194 1.395.57.55.378.884.697 1 .96.063.15.094.385.094.71 0 .694-.11 1.227-.33 1.596-.192.31-.473.555-.844.734-.438.208-1.55.312-3.333.312-.8 0-1.794-.02-2.982-.062l-.143.43c-.254.67-.463 1.112-.625 1.323-.725.937-1.786 1.405-3.183 1.405C5.85 16.99 5 16.076 5 14.256c.003-.94.278-1.814.824-2.618.15-.216.298-.367.444-.454.225-.133.288-.09.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/apex/images/icons/bold-armn-to.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-armn-to.png
new file mode 100644
index 00000000..5e16e38f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-armn-to.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-armn-to.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-armn-to.svg
new file mode 100644
index 00000000..7471d1a3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-.06.257-.15.367-.278.114-.13.205-.302.273-.516.073-.214.11-.48.11-.798V13h-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.214.18.39.29.53.12.132.25.23.387.29.14.05.276.073.406.073m-2.97-7.84c-.37.082-.694.247-.975.45-.28.198-.505.47-.672.813-.16.342-.242.78-.242 1.31V18H6v-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.344.49.734.64 1.17.15.43.226 1.09.226 1.61h1.357v2.04H17.78v1.6c0 .58-.103 1.09-.31 1.54-.21.44-.49.81-.845 1.113-.35.302-.834.53-1.297.687-.464.15-.953.227-1.47.227-.51 0-.996-.08-1.46-.235-.464-.156-.87-.39-1.22-.703-.348-.315-.626-.705-.835-1.174-.203-.473-.304-1.028-.304-1.663s.1-1.182.32-1.64c.21-.46.493-.685.85-.977.35-.297.76-.513 1.22-.648.454-.14.93-.21 1.43-.21h1.13c-.01-.49-.04-1.044-.24-1.36-.2-.324-.457-.58-.77-.767-.31-.192-.598-.33-.984-.425-.375-.09-.578-.094-1.1-.094-.52 0-.64.02-1.01.103z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-b.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-b.png
new file mode 100644
index 00000000..b1c6955b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-b.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-b.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-b.svg
new file mode 100644
index 00000000..1806709a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.01-1.975-1.99-3 2-.975 1.99-1.935 1.99-3 0-2-2-3-4-3H7v12zm7-8c0 1 0 1-2 1h-2V8h2c2 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/apex/images/icons/bold-cyrl-be.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-be.png
new file mode 100644
index 00000000..07a721b5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-be.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-be.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-be.svg
new file mode 100644
index 00000000..383ef323
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.65c.892 0 1.632.11 2.22.327.587.218 1.087.622 1.5 1.21.42.59.63 1.188.63 1.98 0 .812-.21 1.397-.63 1.976-.418.578-.897.974-1.436 1.187-.533.213-1.295.32-2.286.32h-5.65m4.768-2c.75 0 1.28-.05 1.584-.12.305-.077.57-.247.792-.51.23-.26.343-.472.343-.854 0-.557-.2-.868-.596-1.12-.396-.255-1.068-.397-2.02-.397H10v3"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-te.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-te.png
new file mode 100644
index 00000000..6058d8f1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-te.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-te.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-te.svg
new file mode 100644
index 00000000..63aee3ea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 18V8H7V6h11v2h-4v10"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-zhe.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-zhe.png
new file mode 100644
index 00000000..41e562bc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-zhe.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-zhe.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-cyrl-zhe.svg
new file mode 100644
index 00000000..e3499050
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-.18.705-.447.168-.266.4-.873.698-1.82.39-1.242.79-2.034 1.197-2.375.403-.336 1.075-.504 2.014-.504L18 6v1.78l-.386-.008c-.4 0-.69.062-.878.187-.186.115-.337.3-.452.55-.115.25-.286.76-.512 1.536-.12.41-.25.755-.392 1.032-.137.275-.383.536-.738.78.44.156.8.465 1.084.926.288.454.603 1.102.944 1.942L18 18h-2.314l-1.17-3.08-.113-.253-.24-.56c-.247-.57-.45-.933-.61-1.09-.16-.157-.318-.236-.553-.236V18h-2v-5.22c-.226 0-.382.077-.546.23-.164.15-.368.517-.612 1.097l-.246.56-.113.253L8.313 18H6l1.33-3.267c.327-.808.635-1.447.923-1.92.293-.476.663-.793 1.11-.95-.355-.244-.603-.5-.745-.772-.137-.272-.268-.62-.392-1.04-.222-.76-.39-1.263-.505-1.52-.11-.252-.26-.44-.45-.57-.184-.12-.49-.183-.915-.183L6 7.782v-1.78l.386.008c.953 0 1.63.17 2.034.512.4.347.79 1.136 1.177 2.366.3.954.534 1.564.698 1.83.168.26.377.405.705.438V6.002"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-f.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-f.png
new file mode 100644
index 00000000..e650eb60
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-f.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-f.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-f.svg
new file mode 100644
index 00000000..89061f10
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 8V6H8v12h3v-5h4v-2h-4V8z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-g.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-g.png
new file mode 100644
index 00000000..cc4be630
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-g.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-g.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-g.svg
new file mode 100644
index 00000000..05b46e2d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.26-.94.358-1.896.537-2.864.537-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.26-2.282.77-3.222.517-.94 1.27-1.66 2.26-2.16.753-.386 1.692-.58 2.815-.58 1.46 0 2.6.304 3.418.91.825.603 1.354 1.436 1.59 2.502l-2.36.435c-.165-.57-.48-1.018-.94-1.346-.453-.336-1.022-.5-1.707-.5-1.038 0-1.864.322-2.48.97-.61.65-.914 1.613-.914 2.89 0 1.377.31 2.41.93 3.103.62.686 1.434 1.03 2.44 1.03.497 0 .995-.096 1.49-.286.505-.196 1.334-.57 1.69-.846v-.866"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-geor-man.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-geor-man.png
new file mode 100644
index 00000000..d6dcb5db
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-geor-man.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-geor-man.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-geor-man.svg
new file mode 100644
index 00000000..deb95b70
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.06c0-1.714-.394-2.572-1.182-2.572-.868 0-1.302.78-1.302 2.338-.01 1.624.42 2.436 1.295 2.436.793 0 1.19-.734 1.19-2.2m2.167 0C16 16.686 14.884 18 12.65 18 10.218 18 9 16.614 9 13.84c0-2.737 1.217-4.105 3.65-4.105.842 0 1.183.63 1.183.63v-1.58c0-.788-.45-1.183-1.347-1.183-.572 0-.858.374-.858 1.123h-2.34C9.29 6.908 10.35 6 12.462 6 14.83 6 16.01 6.946 16 8.84"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-l.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-l.png
new file mode 100644
index 00000000..ff021ce3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-l.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-l.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-l.svg
new file mode 100644
index 00000000..76956234
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 18V6h3v10h5v2"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-n.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-n.png
new file mode 100644
index 00000000..7ae9321b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-n.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-n.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-n.svg
new file mode 100644
index 00000000..62f66a2f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 18V6h3l4 8V6h3v12h-3l-4-8v8H7"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-v.png b/resources/lib/oojs-ui/themes/apex/images/icons/bold-v.png
new file mode 100644
index 00000000..39c2be04
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/bold-v.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/bold-v.svg b/resources/lib/oojs-ui/themes/apex/images/icons/bold-v.svg
new file mode 100644
index 00000000..027db273
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 18L6 6h3l3 8 3-8h3l-4.5 12"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/calendar-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/calendar-ltr.png
new file mode 100644
index 00000000..8b3ed72f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/calendar-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/calendar-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/calendar-ltr.svg
new file mode 100644
index 00000000..121180e0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/calendar-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 5v10c0 1.7 1.3 3 3 3h14V8c0-1.7-1.3-3-3-3H4zm2 1c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zm4 0c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zm4 0c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zm4 0c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zM5 9h3v2H5V9zm4 0h3v2H9V9zm4 0h3v2h-3V9zm4 0h3v2h-3V9zM5 12h3v2H5v-2zm4 0h3v2H9v-2zm4 0h3v2h-3v-2zm4 0h3v2h-3v-2zM5 15h3v2H7c-1.195 0-2-.805-2-2zm4 0h3v2H9v-2zm4 0h3v2h-3v-2zm4 0h3v2h-3v-2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/calendar-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/calendar-rtl.png
new file mode 100644
index 00000000..8ec5023b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/calendar-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/calendar-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/calendar-rtl.svg
new file mode 100644
index 00000000..9b736bf2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/calendar-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 5v10c0 1.7-1.3 3-3 3H4V8c0-1.7 1.3-3 3-3h14zm-2 1c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm-4 0c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm-4 0c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zM7 6c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm13 3h-3v2h3V9zm-4 0h-3v2h3V9zm-4 0H9v2h3V9zM8 9H5v2h3V9zm12 3h-3v2h3v-2zm-4 0h-3v2h3v-2zm-4 0H9v2h3v-2zm-4 0H5v2h3v-2zm12 3h-3v2h1c1.195 0 2-.805 2-2zm-4 0h-3v2h3v-2zm-4 0H9v2h3v-2zm-4 0H5v2h3v-2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/cancel.png b/resources/lib/oojs-ui/themes/apex/images/icons/cancel.png
new file mode 100644
index 00000000..76b87e46
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/cancel.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/cancel.svg b/resources/lib/oojs-ui/themes/apex/images/icons/cancel.svg
new file mode 100644
index 00000000..5d0bbd9b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/cancel.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="cancel">
+ <path id="circle-with-strike" d="M12 5.022c-3.855 0-6.98 3.124-6.98 6.978 0 3.853 3.124 6.978 6.977 6.978s6.978-3.125 6.978-6.978c0-3.854-3.125-6.978-6.98-6.978zM6.885 12c0-1.092.572-3.25.93-2.93l7.113 7.114c.487.525-1.838.93-2.93.93-2.826 0-5.114-2.29-5.114-5.114zm9.298 2.93L9.07 7.815c-.445-.483 1.837-.93 2.93-.93 2.826 0 5.114 2.288 5.114 5.113 0 1.092-.364 3.542-.93 2.93z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/caret-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/caret-ltr.png
new file mode 100644
index 00000000..d90b3714
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/caret-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/caret-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/caret-ltr.svg
new file mode 100644
index 00000000..44d2d1a9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.8L7 13.1z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/caret-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/caret-rtl.png
new file mode 100644
index 00000000..9064f617
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/caret-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/caret-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/caret-rtl.svg
new file mode 100644
index 00000000..88c7c73f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.1L7.6 22c-.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/apex/images/icons/caretDown.png b/resources/lib/oojs-ui/themes/apex/images/icons/caretDown.png
new file mode 100644
index 00000000..bc453ea5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/caretDown.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/caretDown.svg b/resources/lib/oojs-ui/themes/apex/images/icons/caretDown.svg
new file mode 100644
index 00000000..27cb0805
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 0L12 13.2l-6.1-6c-.8-.8-2-.8-2.8 0L12 16z" id="path4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/caretUp.png b/resources/lib/oojs-ui/themes/apex/images/icons/caretUp.png
new file mode 100644
index 00000000..efd2356b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/caretUp.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/caretUp.svg b/resources/lib/oojs-ui/themes/apex/images/icons/caretUp.svg
new file mode 100644
index 00000000..1d630937
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 0L12 9.3l-6.1 6c-.8.8-2 .8-2.8 0L12 6.5z" id="path4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/case-sensitive.png b/resources/lib/oojs-ui/themes/apex/images/icons/case-sensitive.png
new file mode 100644
index 00000000..f36e52cb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/case-sensitive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/case-sensitive.svg b/resources/lib/oojs-ui/themes/apex/images/icons/case-sensitive.svg
new file mode 100644
index 00000000..2f0e406d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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="M7.53 7L4 17h2.063l.72-2.406h3.624l.72 2.406h2.062L9.654 7H7.533zm1.064 1.53L9.938 13H7.25l1.344-4.47z"/>
+ <path id="lower-case" d="M18.55 17l-.184-1.035h-.055c-.35.44-.71.747-1.08.92-.37.167-.85.25-1.443.25-.564 0-.955-.208-1.377-.625-.42-.418-.628-1.012-.628-1.784 0-.808.283-1.403.846-1.784.568-.386 1.193-.607 2.208-.64l1.322-.04v-.335c0-.772-.395-1.158-1.186-1.158-.61 0-1.325.18-2.147.55l-.688-1.4c.877-.46 1.85-.69 2.916-.69 1.024 0 1.59.22 2.134.665.545.445.818 1.12.818 2.03V17h-1.45m-.394-3.527l-.802.027c-.604.018-1.054.127-1.35.327-.294.2-.442.504-.442.912 0 .582.336.874 1.008.874.48 0 .865-.138 1.152-.415.29-.277.436-.645.436-1.103v-.627"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/check.png b/resources/lib/oojs-ui/themes/apex/images/icons/check.png
new file mode 100644
index 00000000..7ecd3122
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/check.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/check.svg b/resources/lib/oojs-ui/themes/apex/images/icons/check.svg
new file mode 100644
index 00000000..d4559040
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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="M7.105 13.473l1.422-1.423 1.9 1.902L15.237 7l1.66 1.148L10.634 17z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/circle.png b/resources/lib/oojs-ui/themes/apex/images/icons/circle.png
new file mode 100644
index 00000000..3bdc8e28
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/circle.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/circle.svg b/resources/lib/oojs-ui/themes/apex/images/icons/circle.svg
new file mode 100644
index 00000000..18133cc9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/circle.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">
+ <circle cx="12" cy="12" r="6"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/close.png b/resources/lib/oojs-ui/themes/apex/images/icons/close.png
new file mode 100644
index 00000000..86dc8b39
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/close.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/close.svg b/resources/lib/oojs-ui/themes/apex/images/icons/close.svg
new file mode 100644
index 00000000..d058d65b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/close.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="close">
+ <path id="cross" d="M17.717 7.697l-1.414-1.414L12 10.586 7.697 6.283 6.283 7.697 10.586 12l-4.303 4.303 1.414 1.414L12 13.414l4.303 4.303 1.414-1.414L13.414 12z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/code.png b/resources/lib/oojs-ui/themes/apex/images/icons/code.png
new file mode 100644
index 00000000..6e678e2a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/code.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/code.svg b/resources/lib/oojs-ui/themes/apex/images/icons/code.svg
new file mode 100644
index 00000000..d3893b0f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/code.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">
+ <g id="code">
+ <path id="left-bracket" d="M4 12v-1h1c1 0 1 0 1-1V7.614c0-.514.024-.896.073-1.142.054-.252.14-.463.257-.633.204-.28.473-.48.808-.588C7.473 5.14 8.01 5 8.973 5H10v1h-.752c-.457 0-.77.19-.936.408C8.145 6.623 8 6.853 8 7.476v1.857c0 .73-.04 1.18-.244 1.493-.2.307-.562.53-1.09.667.535.155.9.385 1.096.688.2.307.238.76.238 1.488v1.862c0 .62.145.847.312 1.06.166.22.48.407.936.407L10 17v1H8.973c-.963 0-1.5-.133-1.835-.248-.335-.11-.604-.307-.808-.59-.118-.166-.203-.375-.257-.626-.05-.253-.073-.636-.073-1.15V13c0-1 0-1-1-1H4z"/>
+ <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/apex/images/icons/collapse.png b/resources/lib/oojs-ui/themes/apex/images/icons/collapse.png
new file mode 100644
index 00000000..4dad20f4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/collapse.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/collapse.svg b/resources/lib/oojs-ui/themes/apex/images/icons/collapse.svg
new file mode 100644
index 00000000..645bfda5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/collapse.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="collapse">
+ <path id="arrow" d="M6.697 15.714L12 10.412l5.303 5.302 1.414-1.414L12 7.583 5.283 14.3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/comment.png b/resources/lib/oojs-ui/themes/apex/images/icons/comment.png
new file mode 100644
index 00000000..265a3e41
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/comment.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/comment.svg b/resources/lib/oojs-ui/themes/apex/images/icons/comment.svg
new file mode 100644
index 00000000..c52ce1c1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/comment.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="comment">
+ <path id="speech-bubble" d="M15 6H9C7.343 6 6 7.344 6 9v4c0 1.656 1.343 3 3 3v3l3-3h3c1.657 0 3-1.344 3-3V9c0-1.656-1.343-3-3-3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/downTriangle.png b/resources/lib/oojs-ui/themes/apex/images/icons/downTriangle.png
new file mode 100644
index 00000000..9408199e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/downTriangle.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/downTriangle.svg b/resources/lib/oojs-ui/themes/apex/images/icons/downTriangle.svg
new file mode 100644
index 00000000..e1fb989c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-10H4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/edit-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/edit-ltr.png
new file mode 100644
index 00000000..afaddc5a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/edit-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/edit-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/edit-ltr.svg
new file mode 100644
index 00000000..4cd6cdac
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 2L5 14l-1 5 5-1L21 6c0-2-2-4-4-4zM7.2 15.5c-.3-.3-.7-.6-1-.8C8.5 12.4 17.5 3.3 17.5 3.3c.4.1.7.3 1 .7L7.2 15.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/edit-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/edit-rtl.png
new file mode 100644
index 00000000..47559372
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/edit-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/edit-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/edit-rtl.svg
new file mode 100644
index 00000000..932997b1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-1L4 6c0-2 2-4 4-4zm9.8 13.5c.3-.3.7-.6 1-.8C16.5 12.4 7.5 3.3 7.5 3.3c-.4.1-.7.3-1 .7l11.3 11.5z" id="path173"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/editLock-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/editLock-ltr.png
new file mode 100644
index 00000000..966bfcbc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/editLock-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/editLock-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/editLock-ltr.svg
new file mode 100644
index 00000000..1b1cb76e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 4V3s0-3-3-3-3 3-3 3v1h-1v6h8V4zm-1.5 0h-3V3s0-1.5 1.5-1.5c1.48.06 1.5 1.5 1.5 1.5zM13 9.6l-6.8 6.9c-.3-.3-.7-.6-1-.8 1.4-1.4 5-5 7.8-7.9V6l-9 9-1 5 5-1 8-8h-3z" id="path186"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/editLock-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/editLock-rtl.png
new file mode 100644
index 00000000..961abe69
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/editLock-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/editLock-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/editLock-rtl.svg
new file mode 100644
index 00000000..84a68164
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 4V3s0-3 3-3 3 3 3 3v1h1v6H3V4zm1.5 0h3V3s0-1.5-1.5-1.5C5.52 1.56 5.5 3 5.5 3zM12 9.6l6.8 6.9c.3-.3.7-.6 1-.8-1.4-1.4-5-5-7.8-7.9V6l9 9 1 5-5-1-8-8h3z" id="path186"/>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/editUndo-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/editUndo-ltr.png
new file mode 100644
index 00000000..e3dc95a2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/editUndo-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/editUndo-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/editUndo-ltr.svg
new file mode 100644
index 00000000..05778cd8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-.3L8 3l1.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.8H9.1L5 15l-1 5 5-1 7.8-7.8-1.6-.1zM20.6 6c-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/apex/images/icons/editUndo-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/editUndo-rtl.png
new file mode 100644
index 00000000..6dd8b464
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/editUndo-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/editUndo-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/editUndo-rtl.svg
new file mode 100644
index 00000000..ac03c05a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-.3L17 3l-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.8L20 15l1 5-5-1-7.8-7.8 1.6-.1zM4.4 6c1.7 0 3.2.5 4.4 1.4l.9.9-.8 1.3L8 11 4 7c0-.3.1-.7.2-1h.2z" id="path206"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/ellipsis.png b/resources/lib/oojs-ui/themes/apex/images/icons/ellipsis.png
new file mode 100644
index 00000000..1e4050c9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/ellipsis.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/ellipsis.svg b/resources/lib/oojs-ui/themes/apex/images/icons/ellipsis.svg
new file mode 100644
index 00000000..dd36a30d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/expand.png b/resources/lib/oojs-ui/themes/apex/images/icons/expand.png
new file mode 100644
index 00000000..9073d243
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/expand.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/expand.svg b/resources/lib/oojs-ui/themes/apex/images/icons/expand.svg
new file mode 100644
index 00000000..84b9e0a6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/expand.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="expand">
+ <path id="arrow" d="M17.303 8.283L12 13.586 6.697 8.283 5.283 9.697 12 16.414l6.717-6.717z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/external-link-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/external-link-ltr.png
new file mode 100644
index 00000000..4b59b2a2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/external-link-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/external-link-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/external-link-ltr.svg
new file mode 100644
index 00000000..1d7980dc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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="24" height="24" viewBox="0 0 24 24">
+ <g id="external">
+ <path id="box" d="M4 4h6v2H6v12h12v-4h2v6H4z"/>
+ <path id="arrow" d="M12.42 4H20v7.58l-2.84-2.846L12.892 13 11 11.106l4.264-4.266z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/external-link-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/external-link-rtl.png
new file mode 100644
index 00000000..29786548
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/external-link-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/external-link-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/external-link-rtl.svg
new file mode 100644
index 00000000..7e25d034
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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="24" height="24" viewBox="0 0 24 24">
+ <g id="external">
+ <path id="box" d="M20 4h-6v2h4v12H6v-4H4v6h16z"/>
+ <path id="arrow" d="M11.58 4H4v7.58l2.84-2.846L11.108 13 13 11.106 8.736 6.84z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/find-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/find-ltr.png
new file mode 100644
index 00000000..9f418b88
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/find-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/find-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/find-ltr.svg
new file mode 100644
index 00000000..67e69434
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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="M13.656 11c-1.92 0-3.5 1.548-3.5 3.47 0 1.92 1.58 3.5 3.5 3.5.75 0 1.432-.253 2-.657l.094.156 2.375 2.37c.19.19.534.154.78-.093s.315-.59.126-.78l-2.37-2.377-.188-.093c.402-.567.655-1.283.655-2.03 0-1.92-1.55-3.47-3.47-3.47zm0 1.656c1.01 0 1.813.8 1.813 1.813 0 1.01-.805 1.84-1.817 1.84-1.01 0-1.844-.83-1.844-1.844s.832-1.814 1.844-1.814z"/>
+ <path id="text" d="M6 5v2h10V5H6zm0 3v2h11V8H6zm0 3v2h3.53c.284-.797.787-1.486 1.44-2H6zm0 3v2h3.53c-.177-.48-.28-.99-.28-1.53 0-.16.046-.315.063-.47H6z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/find-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/find-rtl.png
new file mode 100644
index 00000000..b63eb841
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/find-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/find-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/find-rtl.svg
new file mode 100644
index 00000000..962165d6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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="M11.344 11c1.92 0 3.5 1.548 3.5 3.47 0 1.92-1.58 3.5-3.5 3.5-.75 0-1.432-.253-2-.657l-.094.156-2.375 2.37c-.19.19-.534.154-.78-.093s-.315-.59-.126-.78l2.37-2.377.188-.093c-.402-.567-.655-1.283-.655-2.03 0-1.92 1.55-3.47 3.47-3.47zm0 1.656c-1.01 0-1.813.8-1.813 1.813 0 1.01.805 1.84 1.817 1.84 1.01 0 1.844-.83 1.844-1.844s-.832-1.814-1.844-1.814z"/>
+ <path id="text" d="M19 5v2H9V5zm0 3v2H8V8zm0 3v2h-3.53c-.284-.797-.787-1.486-1.44-2zm0 3v2h-3.53c.177-.48.28-.99.28-1.53 0-.16-.046-.315-.063-.47z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/flag-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/flag-ltr.png
new file mode 100644
index 00000000..63ceaafb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/flag-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/flag-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/flag-ltr.svg
new file mode 100644
index 00000000..bcd728ec
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.5V5c-1.4-1.5-5.2-1.2-6 0V4H7v15h1v-7c.8-.8 3.4-.9 5-.5V13c1.2 1.5 4.3 1.2 5 0V6c-.7.7-2.7.9-4 .5z" id="path216"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/flag-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/flag-rtl.png
new file mode 100644
index 00000000..80835c0c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/flag-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/flag-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/flag-rtl.svg
new file mode 100644
index 00000000..3a93b6f7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.5V5c1.4-1.5 5.2-1.2 6 0V4h1v15h-1v-7c-.8-.8-3.4-.9-5-.5V13c-1.2 1.5-4.3 1.2-5 0V6c.7.7 2.7.9 4 .5z" id="path216"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-ltr.png
new file mode 100644
index 00000000..6f84122e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-ltr.svg
new file mode 100644
index 00000000..87245de9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.5V5c-1.4-1.5-5.2-1.2-6 0V4H7v15h1v-7c.8-.8 3.4-.9 5-.5V13c1.2 1.5 4.3 1.2 5 0V6c-.7.7-2.7.9-4 .5z"/>
+ </g>
+ <g id="Layer_2">
+ <g id="g230">
+ <path id="path232" d="M17.997 1.99l.99.99-15.98 15.98-.99-.99z"/>
+ </g>
+ <g id="g234">
+ <path id="path236" d="M17 1.016l.99.99-15.98 15.98-.99-.99z" fill="#fff"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-rtl.png
new file mode 100644
index 00000000..89674cc7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/flagUndo-rtl.svg
new file mode 100644
index 00000000..06da23a6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.5V5c1.4-1.5 5.2-1.2 6 0V4h1v15h-1v-7c-.8-.8-3.4-.9-5-.5V13c-1.2 1.5-4.3 1.2-5 0V6c.7.7 2.7.9 4 .5z"/>
+ </g>
+ <g id="Layer_2">
+ <g id="g230">
+ <path id="path232" d="M7.003 1.99l-.99.99 15.98 15.98.99-.99z"/>
+ </g>
+ <g id="g234">
+ <path id="path236" d="M8 1.016l-.99.99 15.98 15.98.99-.99z" fill="#fff"/>
+ </g>
+ </g>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/help-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/help-ltr.png
new file mode 100644
index 00000000..4428ef32
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/help-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/help-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/help-ltr.svg
new file mode 100644
index 00000000..825435da
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/help-ltr.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="M12 2.085c-5.477 0-9.915 4.438-9.915 9.916 0 5.48 4.438 9.918 9.916 9.918 5.48 0 9.918-4.438 9.918-9.914 0-5.477-4.438-9.915-9.914-9.915zm.002 18c-4.465 0-8.084-3.62-8.084-8.083 0-4.465 3.62-8.084 8.084-8.084 4.464 0 8.083 3.62 8.083 8.084 0 4.464-3.62 8.083-8.083 8.083z"/>
+ <g id="question-mark">
+ <path id="top" d="M11.766 6.688c-2.5 0-3.22 2.188-3.22 2.188l1.412.854s.298-.79.9-1.23c.517-.374 1.626-.624 2.22.126.7.885-.17 1.587-1.078 2.72C11.047 12.53 11 15 11 15h1.97s.134-2.318 1.04-3.38c.603-.708 1.443-1.34 1.443-2.495s-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/apex/images/icons/help-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/help-rtl.png
new file mode 100644
index 00000000..e6ab21be
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/help-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/help-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/help-rtl.svg
new file mode 100644
index 00000000..0d8052f1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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="M12 2.085c5.477 0 9.915 4.438 9.915 9.916 0 5.48-4.438 9.918-9.916 9.918-5.48 0-9.918-4.438-9.918-9.914 0-5.477 4.438-9.915 9.914-9.915zm-.002 18c4.465 0 8.084-3.62 8.084-8.083 0-4.465-3.62-8.084-8.084-8.084-4.464 0-8.083 3.62-8.083 8.084 0 4.464 3.62 8.083 8.083 8.083z"/>
+ <g id="question-mark">
+ <path id="top" d="M12.234 6.688c2.5 0 3.22 2.188 3.22 2.188l-1.412.854s-.298-.79-.9-1.23c-.517-.374-1.626-.624-2.22.126-.7.885.17 1.587 1.078 2.72C12.953 12.53 13 15 13 15h-1.97s-.134-2.318-1.04-3.38c-.603-.708-1.443-1.34-1.443-2.495 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/apex/images/icons/history.png b/resources/lib/oojs-ui/themes/apex/images/icons/history.png
new file mode 100644
index 00000000..0e177aba
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/history.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/history.svg b/resources/lib/oojs-ui/themes/apex/images/icons/history.svg
new file mode 100644
index 00000000..10d1b81e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/history.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="history">
+ <path id="clock-hands" d="M17.26 15.076s-2.385-1.935-4.005-3.062c.72-2.397 1.702-6.56 1.702-6.56s-4.35 5.364-4.877 6.7c-.463 1.168 1.46 2.21 2.346 1.678 1.9.55 4.834 1.244 4.834 1.244z"/>
+ <path id="arrow" d="M12.086 2.085C6.608 2.085 2.17 6.523 2.17 12c0 1.784.476 3.455 1.3 4.9l-2.22 2.04h5.688v-5.22L4.87 15.616c-.55-1.088-.866-2.312-.866-3.615 0-4.46 3.62-8.08 8.084-8.08 4.464 0 8.083 3.62 8.083 8.084 0 4.465-3.615 8.084-8.08 8.084-1.144 0-2.23-.247-3.212-.678l-.833 1.633c1.235.557 2.602.874 4.045.874C17.562 21.914 22 17.477 22 12c0-5.477-4.438-9.915-9.914-9.915z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/indent-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/indent-ltr.png
new file mode 100644
index 00000000..a7bb6ec9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/indent-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/indent-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/indent-ltr.svg
new file mode 100644
index 00000000..87da9eff
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/indent-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="indent-list-ltr">
+ <path id="arrow" d="M5 15.08l4.794-3.528-4.704-3.6L5.08 10H3v3h2z"/>
+ <path id="bottom_line" d="M20 17H4c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h16c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1z"/>
+ <path id="middle_line" d="M20 10h-7c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h7c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1z"/>
+ <path id="top_line" d="M20 3H4c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h16c.553 0 1-.447 1-1V4c0-.553-.447-1-1-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/indent-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/indent-rtl.png
new file mode 100644
index 00000000..003343c3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/indent-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/indent-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/indent-rtl.svg
new file mode 100644
index 00000000..77cc2126
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/indent-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="indent-list-rtl">
+ <path id="arrow" d="M19 15.08l-4.794-3.528 4.704-3.6.01 2.048H21v3h-2z"/>
+ <path id="bottom_line" d="M4 17h16c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H4c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
+ <path id="middle_line" d="M4 10h7c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H4c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
+ <path id="top_line_5_" d="M4 3h16c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H4c-.553 0-1-.447-1-1V4c0-.553.447-1 1-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/info.png b/resources/lib/oojs-ui/themes/apex/images/icons/info.png
new file mode 100644
index 00000000..f0211899
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/info.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/info.svg b/resources/lib/oojs-ui/themes/apex/images/icons/info.svg
new file mode 100644
index 00000000..6cff2ffa
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/info.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="info">
+ <path id="circled-i" d="M11.5 17C8.462 17 6 14.536 6 11.5 6 8.463 8.462 6 11.5 6c3.036 0 5.5 2.462 5.5 5.5 0 3.036-2.464 5.5-5.5 5.5zm0-12C7.91 5 5 7.91 5 11.5S7.91 18 11.5 18s6.5-2.91 6.5-6.5S15.09 5 11.5 5zm.5 5v4h1v1h-3v-1h1v-3h-1v-1zm-1-2h1v1h-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/insert.png b/resources/lib/oojs-ui/themes/apex/images/icons/insert.png
new file mode 100644
index 00000000..97927a84
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/insert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/insert.svg b/resources/lib/oojs-ui/themes/apex/images/icons/insert.svg
new file mode 100644
index 00000000..d1e9ba33
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-2v6H5v2h6v6h2v-6h6v-2h-6z" id="plus"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-a.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-a.png
new file mode 100644
index 00000000..a81e803d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-a.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-a.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-a.svg
new file mode 100644
index 00000000..a3a11c68
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 12H8l2.333-4h4L15 18h1.667l-2-12zm-3.75 7l2.527-4.333.723 4.333h-3.25z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-keheh-jeem.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-keheh-jeem.png
new file mode 100644
index 00000000..9f603eab
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-keheh-jeem.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-keheh-jeem.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-keheh-jeem.svg
new file mode 100644
index 00000000..99980c05
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.3-.77.712-.87 1.125-.065.263-.036.572.062.78.19.406.54.575.844.814l.094-.12.53.624c.14.165.344.514.47.94.137.462.08.724 0 1.124h-3.44c-.34 0-.593.007-.767-.02-.34-.053-.256-.208-.234-.34.33-.127.56-.173.934-.14.29-.495.593-.886.906-1.314-.98.037-1.877.015-2.687-.094-.346-.048-.698-.187-1.094-.157-.358.026-.77.24-1.03.72-.248.447-.436.838-.658 1.28l.75-.47c.23-.14.484-.226.72-.218.156.005.274.054.405.094-.233.203-.51.4-.72.56-.3.26-.703.69-.907 1-.402.616-.693 1.085-.874 1.78-.18.69.003 1.34.468 1.75.426.378.846.52 1.28.565.65.065 1.206.093 2-.188.658-.23 1.022-.553 1.5-.97-.882.11-1.816.09-2.53.032-.87-.07-1.268-.385-1.47-.595-.27-.283-.306-.64-.155-1.22.035-.14.096-.322.25-.53.17-.228.363-.435.593-.656.45-.437 1.01-.738 1.46-.94-.044.206-.106.443-.054.688.05.23.25.38.44.47.26.12.505.153.69.154 1.42.01 2.86 0 4.28 0 .245 0 .45-.163.592-.375.14-.21.25-.48.344-.845.13-.5.094-1.062-.094-1.625-.182-.543-.418-1.01-.72-1.406-.334-.442-.673-.83-1-1.22 1.258-.813 2.717-1.237 3.97-1.686.12-.452.224-.926.313-1.313zm-9.47 8.438c-.26.394-.583.69-.874 1 .38.286.75.556 1.098.813.335-.303.626-.674.875-.97-.39-.267-.77-.587-1.093-.843z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-meem.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-meem.png
new file mode 100644
index 00000000..03493be1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-meem.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-meem.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-arab-meem.svg
new file mode 100644
index 00000000..a9c7deff
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.73l-.93 2.19h-4.663c-.48 0-.857.12-1.135.366l-.06.11c-.185 2.016-.503 3.558-.956 4.627-.272.64-.633 1.252-1.082 1.833-.177.226-.22.186-.126-.12l.142-.503.17-.67.234-.87.002-.008.202-1.045.258-1.41.353-1.907c.19-.312.42-.638.695-.98.276-.342.59-.706.94-1.09.13-.092.697-.18 1.705-.266 1.05-.086 1.64-.183 1.766-.293l.065-.128c.01-.11-.01-.24-.052-.394-.044-.153-.12-.327-.232-.522-.22-.428-.438-.64-.654-.64-.293 0-.914.268-1.863.805-.36.208-.377.125-.05-.247 1.556-1.71 2.706-2.566 3.45-2.566.38 0 .67.13.86.394.135.195.25.6.344 1.21l.203 1.2c.105.586.24.895.408.925"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-armn-sha.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-armn-sha.png
new file mode 100644
index 00000000..b5e55cca
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-armn-sha.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-armn-sha.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-armn-sha.svg
new file mode 100644
index 00000000..a653a27d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.587 6h1.723c.558 0 1.042.032 1.45.095.416.063.794.173 1.136.33l4.483 2.033-.328 1.67-2.624-1.165c-.126-.058-.27-.103-.433-.134-.164-.04-.356-.06-.576-.06-.583 0-1.137.094-1.663.283-.526.19-1 .46-1.427.812-.42.35-.776.78-1.07 1.283-.294.504-.504 1.074-.63 1.71-.24 1.255-.15 2.21.27 2.87.424.65 1.19.976 2.292.976.55 0 1.045-.08 1.48-.237.437-.157.815-.378 1.136-.66.325-.29.59-.634.795-1.034.21-.4.362-.84.457-1.323l.11-.56h1.6l-.12.59c-.13.674-.356 1.288-.676 1.845-.32.55-.725 1.024-1.214 1.423-.488.395-1.053.7-1.694.923-.643.216-1.344.324-2.106.324-.767 0-1.434-.114-2-.34-.568-.226-1.025-.554-1.372-.985-.347-.436-.573-.97-.678-1.607-.105-.637-.078-1.364.08-2.184.125-.66.346-1.274.66-1.836.316-.568.697-1.067 1.144-1.497.445-.436.944-.794 1.496-1.072.55-.283 1.13-.474 1.733-.574l-.466-.23"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-c.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-c.png
new file mode 100644
index 00000000..f46dea59
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-c.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-c.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-c.svg
new file mode 100644
index 00000000..0a0d1103
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.48.214c-.467 1.34-1.15 2.354-2.045 3.04-.896.686-1.9 1.03-3.015 1.03-1.36 0-2.438-.43-3.237-1.29C7.4 15.85 7 14.618 7 13.012c0-2.09.606-3.817 1.817-5.184C9.897 6.61 11.237 6 12.84 6c1.186 0 2.145.33 2.878.99.738.66 1.165 1.546 1.282 2.66l-1.397.135c-.148-.84-.453-1.464-.916-1.876-.458-.42-1.05-.63-1.78-.63-1.368 0-2.475.63-3.32 1.893-.733 1.087-1.1 2.377-1.1 3.87 0 1.194.283 2.104.848 2.732.565.628 1.3.942 2.206.942.778 0 1.477-.26 2.1-.785.63-.522 1.08-1.26 1.37-2.216"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-d.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-d.png
new file mode 100644
index 00000000..4ace3f35
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-d.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-d.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-d.svg
new file mode 100644
index 00000000..feadca08
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 18L9.462 6h3.557c.85 0 1.5.063 1.95.188.645.17 1.195.472 1.65.91.457.43.8.97 1.03 1.62.23.65.347 1.378.347 2.186 0 .966-.146 1.847-.436 2.644-.283.79-.66 1.49-1.126 2.095-.46.6-.947 1.072-1.456 1.416-.504.334-1.1.585-1.794.75-.526.125-1.172.19-1.94.19H7m1.86-1.36h1.866c.842 0 1.59-.08 2.245-.24.41-.097.76-.242 1.05-.433.38-.247.727-.57 1.038-.975.408-.535.732-1.143.974-1.825.247-.687.37-1.467.37-2.34 0-.97-.166-1.716-.5-2.235-.332-.524-.755-.87-1.27-1.04-.38-.126-.974-.188-1.78-.188H11L9.095 16.64"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-e.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-e.png
new file mode 100644
index 00000000..882a5354
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-e.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-e.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-e.svg
new file mode 100644
index 00000000..f3851498
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 18L9.474 6H18l-.282 1.367H10.77L10.02 11h6.09l-.28 1.367H9.74l-.88 4.273h7.44L16.018 18H7"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-geor-kan.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-geor-kan.png
new file mode 100644
index 00000000..7f9da2ac
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-geor-kan.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-geor-kan.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-geor-kan.svg
new file mode 100644
index 00000000..65670ef4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.663C14.617 16.888 13.223 18 10.88 18 8.96 18 8 17.213 8 15.64c0-.298.036-.624.108-.977.083-.43.245-.836.488-1.217l1.24.605-.206.617c-.055.26-.083.497-.083.712 0 .97.52 1.457 1.564 1.457 1.31 0 2.105-.723 2.387-2.17l.058-.33c.044-.222.066-.426.066-.614 0-.927-.546-1.39-1.64-1.39h-1.115l.248-1.26h1.118c1.203-.004 1.91-.55 2.12-1.64.04-.18.057-.355.057-.52 0-1.144-.9-1.715-2.697-1.715L11.94 6C14.646 6 16 6.877 16 8.627c0 .248-.027.516-.082.803-.204 1.092-1.05 1.824-2.54 2.194l-.033.166c1.23.2 1.845.823 1.845 1.872 0 .21-.025.433-.074.67l-.058.332"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-i.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-i.png
new file mode 100644
index 00000000..28aab448
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-i.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-i.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-i.svg
new file mode 100644
index 00000000..e670e9bf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 18l.25-.995h-1.5l2.508-10.037h1.5L15.5 6h-5l-.242.968h1.5l-2.51 10.037h-1.5L7.5 18z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-k.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-k.png
new file mode 100644
index 00000000..4f87e9ae
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-k.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-k.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-k.svg
new file mode 100644
index 00000000..38bcd73a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.652L17 6h-2l-5.31 5.234L11 6H9.5l-3 12H8l1.173-4.693 1.54-1.438C11 16 14 18 14 18h2s-4-2-3.982-7.348z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-s.png b/resources/lib/oojs-ui/themes/apex/images/icons/italic-s.png
new file mode 100644
index 00000000..4a7b1fc2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/italic-s.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/italic-s.svg b/resources/lib/oojs-ui/themes/apex/images/icons/italic-s.svg
new file mode 100644
index 00000000..615e5f22
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.59l-.302 1.525c-.522-.28-1.04-.488-1.557-.628-.51-.145-1.007-.217-1.487-.217-.935 0-1.68.204-2.23.612-.554.408-.83.95-.83 1.627 0 .37.1.654.302.86.207.192.733.404 1.58.63l.937.233c1.06.274 1.795.622 2.208 1.046.413.42.62 1.007.62 1.766 0 1.167-.46 2.117-1.38 2.85-.913.734-2.12 1.1-3.617 1.1-.615 0-1.232-.06-1.852-.185-.62-.12-1.242-.3-1.867-.55l.314-1.61c.573.356 1.147.625 1.72.806.578.18 1.154.27 1.728.27.976 0 1.76-.216 2.347-.65.59-.434.883-1 .883-1.697 0-.465-.12-.816-.356-1.054-.233-.243-.737-.462-1.512-.658l-.937-.24c-1.07-.28-1.8-.6-2.19-.964-.39-.367-.584-.878-.584-1.534 0-1.152.442-2.094 1.325-2.828.89-.74 2.043-1.108 3.463-1.108.553 0 1.1.05 1.642.147.542.1 1.085.246 1.627.443"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/language.png b/resources/lib/oojs-ui/themes/apex/images/icons/language.png
new file mode 100644
index 00000000..b4f0875e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/language.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/language.svg b/resources/lib/oojs-ui/themes/apex/images/icons/language.svg
new file mode 100644
index 00000000..956aba1f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.27-.59 1.042.407-.18.363c.66.27 1.1.468 1.312.59.33.21.618.513.86.904.21.393.316.846.316 1.358 0 .786-.302 1.48-.905 2.083-.604.634-1.66 1.057-3.17 1.268-.12-.36-.257-.68-.407-.95.97-.15 1.65-.333 2.04-.545.455-.21.786-.48 1-.813.21-.303.313-.663.313-1.087 0-.482-.135-.905-.406-1.27-.33-.33-.8-.588-1.402-.77-.332.635-.648 1.118-.95 1.45-.242.332-.694.906-1.358 1.72.09.394.18.71.272.952l-1.043.362-.09-.498c-.424.36-.802.617-1.134.77-.36.15-.664.226-.905.226-.303 0-.574-.136-.814-.407-.243-.3-.362-.68-.362-1.132 0-.6.137-1.143.408-1.63.24-.45.603-.89 1.086-1.31.273-.24.726-.53 1.36-.86 0-.27.03-.8.09-1.584-.514.03-.92.045-1.222.045-.393 0-.71-.015-.95-.045l-.047-1.04c.726.09 1.495.134 2.31.134 0-.15.076-.74.228-1.767l1.177.184c-.15.542-.256 1.04-.316 1.493.24-.03.542-.077.905-.138.36-.06.573-.09.634-.09s.647-.15 1.765-.453l.045 1.04c-.966.242-2.144.44-3.53.59-.063.662-.093 1.085-.093 1.265.664-.15 1.285-.225 1.858-.225zm-2.672 3.893c-.06-.48-.132-1.252-.223-2.31-.573.424-1.04.86-1.403 1.313-.302.423-.45.875-.45 1.358 0 .24.043.438.135.588.09.092.194.137.315.137.364 0 .908-.365 1.63-1.09zm.775-2.763c0 .483.03 1.088.09 1.81.604-.904 1.057-1.598 1.36-2.08-.575.06-1.06.15-1.45.27z"/>
+ <path id="english" d="M9.497 15.98h1.85L8.265 7.033h-1.85l-3.08 8.95h1.85L5.74 14h3.21l.547 1.98zm-3.49-3.376L7.34 8.822l1.343 3.782H6.008z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/layout-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/layout-ltr.png
new file mode 100644
index 00000000..dac7b2cc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/layout-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/layout-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/layout-ltr.svg
new file mode 100644
index 00000000..c3be66cc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 19V5h6v8h8v6H5z"/>
+ <path id="float" d="M13 5v6h6V5h-6zm5 5h-4V6h4v4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/layout-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/layout-rtl.png
new file mode 100644
index 00000000..470b7855
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/layout-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/layout-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/layout-rtl.svg
new file mode 100644
index 00000000..ce7feb8d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-6h8V5h6v14H5z"/>
+ <path id="float" d="M5 5v6h6V5H5zm1 1h4v4H6V6z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/link.png b/resources/lib/oojs-ui/themes/apex/images/icons/link.png
new file mode 100644
index 00000000..0b87983a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/link.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/link.svg b/resources/lib/oojs-ui/themes/apex/images/icons/link.svg
new file mode 100644
index 00000000..23c9539b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/link.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="link">
+ <path id="right" d="M19.188 12c0 1.1-.89 2.016-1.988 2.016L13.005 14c.538 1.09.963 2 1.997 2h3C19.658 16 21 13.657 21 12s-1.342-4-2.998-4h-3c-1.034 0-1.46.91-1.998 2l4.195-.016c1.094 0 1.985.917 1.985 2.017z"/>
+ <path id="center" d="M8 12c0 .535.42 1 .938 1h6.11c.517 0 .937-.465.937-1 0-.534-.42-1-.938-1h-6.11C8.42 11 8 11.466 8 12z"/>
+ <path id="left" d="M4.816 12c0-1.1.89-2.016 1.988-2.016L11 10c-.54-1.09-.964-2-1.998-2h-3c-1.656 0-2.998 2.343-2.998 4s1.342 4 2.998 4h3c1.034 0 1.46-.91 1.998-2l-4.195.016c-1.098 0-1.99-.917-1.99-2.017z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-ltr.png
new file mode 100644
index 00000000..c449a423
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-ltr.svg
new file mode 100644
index 00000000..d60fc886
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-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="bullet-list-ltr">
+ <path id="bottom_dot" d="M5 10H4c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h1c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
+ <path id="middle_dot" d="M5 17H4c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h1c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
+ <path id="top_dot" d="M5 3H4c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h1c.552 0 1-.447 1-1V4c0-.553-.448-1-1-1z"/>
+ <path id="bottom_line" d="M20 17H9c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h11c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
+ <path id="middle_line" d="M20 10H9c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h11c.552 0 1-.447 1-1v-1c0-.553-.448-1-1-1z"/>
+ <path id="top_line" d="M20 3H9c-.552 0-1 .447-1 1v1c0 .553.448 1 1 1h11c.552 0 1-.447 1-1V4c0-.553-.448-1-1-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-rtl.png
new file mode 100644
index 00000000..1410d61a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-rtl.svg
new file mode 100644
index 00000000..4818cbbc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/listBullet-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="bullet-list-rtl">
+ <path id="bottom_dot_1_" d="M19 10h1c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1h-1c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
+ <path id="middle_dot_1_" d="M19 17h1c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1h-1c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
+ <path id="top_dot_1_" d="M19 3h1c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1h-1c-.552 0-1-.447-1-1V4c0-.553.448-1 1-1z"/>
+ <path id="bottom_line_7_" d="M4 17h11c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1H4c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
+ <path id="middle_line_7_" d="M4 10h11c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1H4c-.552 0-1-.447-1-1v-1c0-.553.448-1 1-1z"/>
+ <path id="top_line_7_" d="M4 3h11c.552 0 1 .447 1 1v1c0 .553-.448 1-1 1H4c-.552 0-1-.447-1-1V4c0-.553.448-1 1-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-ltr.png
new file mode 100644
index 00000000..bec80efb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-ltr.svg
new file mode 100644
index 00000000..173e5db6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-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="number-list-ltr">
+ <path id="bottom_dot" d="M3 16v1h1.993l.03 1H4v1h1v1H3v1h2.023L6 19.998v-1l-.955-.53.955-.5v-.97L4.993 16z"/>
+ <path id="middle_dot" d="M3 9v1h2.117L3 12.187v1.81l3-.06V13H3.882L6 10.812V9.78L5.332 9z"/>
+ <path id="top_dot" d="M4.993 2h-.648L3.018 3.39l.03.61h1.026l-.068 2H3v1h3V6H4.963z"/>
+ <path id="bottom_line" d="M20.002 17H9c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h11.002c.55 0 .998-.447.998-1v-1c0-.553-.447-1-.998-1z"/>
+ <path id="middle_line" d="M20.002 10H9c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h11.002c.55 0 .998-.447.998-1v-1c0-.553-.447-1-.998-1z"/>
+ <path id="top_line" d="M20.002 3H9c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h11.002c.55 0 .998-.447.998-1V4c0-.553-.447-1-.998-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-rtl.png
new file mode 100644
index 00000000..d807f9ec
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-rtl.svg
new file mode 100644
index 00000000..9e7894ea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/listNumbered-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="number-list-rtl">
+ <path id="bottom_dot" d="M18 16v1h1.993l.03 1H19v1h1v1h-2v1h2.023L21 19.998v-1l-.956-.53.956-.5v-.97L19.993 16z"/>
+ <path id="middle_dot" d="M18 9v1h2.116L18 12.187v1.81l3-.06V13h-2.118L21 10.812V9.78L20.33 9z"/>
+ <path id="top_dot" d="M19.993 2h-.648l-1.328 1.39.03.61h1.027l-.07 2H18v1h3V6h-1.038z"/>
+ <path id="bottom_line" d="M4 17h11c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H4c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
+ <path id="middle_line" d="M4 10h11c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H4c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
+ <path id="top_line" d="M4 3h11c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H4c-.553 0-1-.447-1-1V4c0-.553.447-1 1-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/lock.png b/resources/lib/oojs-ui/themes/apex/images/icons/lock.png
new file mode 100644
index 00000000..2a004040
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/lock.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/lock.svg b/resources/lib/oojs-ui/themes/apex/images/icons/lock.svg
new file mode 100644
index 00000000..85baad26
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/lock.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="lock">
+ <path d="M12 6c-2.21 0-4 1.79-4 4v1H7v7h10v-7h-1v-1c0-2.21-1.79-4-4-4zm0 2c1.105 0 2 .895 2 2v1h-4v-1c0-1.105.895-2 2-2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/menu.png b/resources/lib/oojs-ui/themes/apex/images/icons/menu.png
new file mode 100644
index 00000000..0a781199
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/menu.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/menu.svg b/resources/lib/oojs-ui/themes/apex/images/icons/menu.svg
new file mode 100644
index 00000000..ce25178a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/menu.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="menu">
+ <path id="lines" d="M6 15h12c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H6c-.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-1H6c-.553 0-1 .447-1 1zm0-5v1c0 .553.447 1 1 1h12c.553 0 1-.447 1-1V6c0-.553-.447-1-1-1H6c-.553 0-1 .447-1 1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/move-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/move-ltr.png
new file mode 100644
index 00000000..fc4cd390
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/move-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/move-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/move-ltr.svg
new file mode 100644
index 00000000..670d84d1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/move-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="move-ltr">
+ <path id="arrow" d="M8.935 7.18l5.302 5.303-5.302 5.303L10.35 19.2l6.715-6.717-6.716-6.716z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/move-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/move-rtl.png
new file mode 100644
index 00000000..7aab2175
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/move-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/move-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/move-rtl.svg
new file mode 100644
index 00000000..35b63751
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/move-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="move-rtl">
+ <path id="arrow" d="M15.065 17.786l-5.302-5.303 5.302-5.302-1.415-1.41-6.714 6.717L13.65 19.2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/move.png b/resources/lib/oojs-ui/themes/apex/images/icons/move.png
new file mode 100644
index 00000000..7ba0ee93
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/move.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/move.svg b/resources/lib/oojs-ui/themes/apex/images/icons/move.svg
new file mode 100644
index 00000000..b04ecdd4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-3V7h2l-3-4-3 4h2v3H8V8l-4 3 4 3v-2h3v3H9l3 4 3-4h-2v-3h3v2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/newline-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/newline-ltr.png
new file mode 100644
index 00000000..9e7c67f9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/newline-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/newline-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/newline-ltr.svg
new file mode 100644
index 00000000..1d654eb5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.3H11v-4l-6 5.5 6 5.5v-4h8v-9h-1.2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/newline-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/newline-rtl.png
new file mode 100644
index 00000000..20f5d0db
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/newline-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/newline-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/newline-rtl.svg
new file mode 100644
index 00000000..63e5aa14
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/noWikiText-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-ltr.png
new file mode 100644
index 00000000..8b15525d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-ltr.svg
new file mode 100644
index 00000000..e0e4fc01
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 2V5h-4v2h2zm0 2L9 9 7 7 6 6 5 5 2 2 1 3l2 2H2v14h4v-2H4V7h1l2 2v10h4v-2H9v-6l6 6h-1v2h3l4 4 1-1-4-4zm-5-9V5H7l2 2zm8-2v2h2v10h-2l2 2h2V5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-rtl.png
new file mode 100644
index 00000000..f7bab384
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/noWikiText-rtl.svg
new file mode 100644
index 00000000..a7be5abe
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 2V5h4v2H8zm0 2l7-7 2-2 1-1 1-1 3-3 1 1-2 2h1v14h-4v-2h2V7h-1l-2 2v10h-4v-2h2v-6l-6 6h1v2H7l-4 4-1-1 4-4zm5-9V5h4l-2 2zM5 5v2H3v10h2l-2 2H1V5z" id="path486"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/notice.png b/resources/lib/oojs-ui/themes/apex/images/icons/notice.png
new file mode 100644
index 00000000..7d27f8e9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/notice.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/notice.svg b/resources/lib/oojs-ui/themes/apex/images/icons/notice.svg
new file mode 100644
index 00000000..9334b50e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/notice.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" id="svg3116">
+ <g id="alert">
+ <path d="M12 18c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6zm-1-5h2V8h-2zm0 3h2v-2h-2z" id="path3119"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/outdent-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/outdent-ltr.png
new file mode 100644
index 00000000..03038c1a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/outdent-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/outdent-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/outdent-ltr.svg
new file mode 100644
index 00000000..30b1db6a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/outdent-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="outdent-list-ltr">
+ <path id="arrow" d="M8 13h2v-3H7.948l-.03-2.06-4.713 3.585L8 15.08z"/>
+ <path id="bottom_line" d="M20 17H4c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h16c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1z"/>
+ <path id="middle_line" d="M20 10h-7c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h7c.553 0 1-.447 1-1v-1c0-.553-.447-1-1-1z"/>
+ <path id="top_line" d="M20 3H4c-.553 0-1 .447-1 1v1c0 .553.447 1 1 1h16c.553 0 1-.447 1-1V4c0-.553-.447-1-1-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/outdent-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/outdent-rtl.png
new file mode 100644
index 00000000..58737cbf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/outdent-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/outdent-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/outdent-rtl.svg
new file mode 100644
index 00000000..471fe23c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/outdent-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="outdent-list-rtl">
+ <path id="arrow" d="M16 13h-2v-3h2.052l.03-2.06 4.713 3.585L16 15.08z"/>
+ <path id="bottom_line" d="M4 17h16c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H4c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
+ <path id="middle_line" d="M4 10h7c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H4c-.553 0-1-.447-1-1v-1c0-.553.447-1 1-1z"/>
+ <path id="top_line" d="M4 3h16c.553 0 1 .447 1 1v1c0 .553-.447 1-1 1H4c-.553 0-1-.447-1-1V4c0-.553.447-1 1-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/outline-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/outline-ltr.png
new file mode 100644
index 00000000..a9a186b0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/outline-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/outline-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/outline-ltr.svg
new file mode 100644
index 00000000..44c1591d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 13h14v6H5v-6z"/>
+ <path id="float" d="M5 5v6h6V5H5zm5 5H6V6h4v4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/outline-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/outline-rtl.png
new file mode 100644
index 00000000..b7f025d8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/outline-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/outline-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/outline-rtl.svg
new file mode 100644
index 00000000..c5b19c8f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 19H5v-6h14v6z"/>
+ <path id="float" d="M13 5v6h6V5h-6zm1 1h4v4h-4V6z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/picture.png b/resources/lib/oojs-ui/themes/apex/images/icons/picture.png
new file mode 100644
index 00000000..d680396f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/picture.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/picture.svg b/resources/lib/oojs-ui/themes/apex/images/icons/picture.svg
new file mode 100644
index 00000000..246e130c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/picture.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="picture">
+ <path id="frame" d="M4 5v13h16v-13zm15 12h-14v-11h14z"/>
+ <path id="mountains" d="M9.5 10l2.328 2.312-1.312 1.094.875 1.032 4.109-3.438 2.5 2v3h-12v-2.5z"/>
+ <path id="sky" d="M9.516 7.844l3.046 3.172 2.938-2.016 2.5 2v-4h-12v5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/puzzle-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/puzzle-ltr.png
new file mode 100644
index 00000000..47dad2bf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/puzzle-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/puzzle-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/puzzle-ltr.svg
new file mode 100644
index 00000000..0ea25d70
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.9V6h-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.2H4.1v3.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-.1V18H9c-.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/apex/images/icons/puzzle-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/puzzle-rtl.png
new file mode 100644
index 00000000..51c40db8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/puzzle-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/puzzle-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/puzzle-rtl.svg
new file mode 100644
index 00000000..e6064255
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.9V6h4c-.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-.1V18h-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.8H8.1v-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/apex/images/icons/quotes-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/quotes-ltr.png
new file mode 100644
index 00000000..6c571ce8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/quotes-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/quotes-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/quotes-ltr.svg
new file mode 100644
index 00000000..062d2d96
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/quotes-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.9 8.7c.3-.1.6-.3.8-.6s.3-.7.3-1.1V6c-1.3.2-1.9.2-3.3.8-.9.5-1.6 1.1-2.2 1.8S13 12 13 16v4h6c1.1 0 2-.9 2-2v-6h-4s.1-.9.8-1.8c.6-.7 1.3-1.2 2.1-1.5zM5.5 8.6C4.9 9.3 3 12 3 16v4h6c1.1 0 2-.9 2-2v-6H7s.1-.9.8-1.8c.6-.7 1.3-1.2 2.1-1.5.3-.1.6-.3.8-.6s.3-.7.3-1.1V6c-1.3.2-1.9.2-3.3.8-.8.5-1.6 1.1-2.2 1.8z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/quotes-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/quotes-rtl.png
new file mode 100644
index 00000000..fc46c937
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/quotes-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/quotes-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/quotes-rtl.svg
new file mode 100644
index 00000000..1057ffcf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/quotes-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="g552">
+ <path d="M4.1 8.7c-.3-.1-.6-.3-.8-.6C3.1 7.8 3 7.4 3 7V6c1.3.2 1.9.2 3.3.8.9.5 1.6 1.1 2.2 1.8.6.7 2.5 3.4 2.5 7.4v4H5c-1.1 0-2-.9-2-2v-6h4s-.1-.9-.8-1.8C5.6 9.5 4.9 9 4.1 8.7zm14.4-.1c.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.1V6c1.3.2 1.9.2 3.3.8.8.5 1.6 1.1 2.2 1.8z" id="path554"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-ltr.png
new file mode 100644
index 00000000..7fd47541
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-ltr.svg
new file mode 100644
index 00000000..bacec22d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.6C2.9 9.3 1 12 1 16v4h6c1.1 0 2-.9 2-2v-6H5s.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.1V6c-1.3.2-1.9.2-3.3.8-.8.5-1.6 1.1-2.2 1.8zM19 5V1h-2v4h-4v2h4v4h2V7h4V5zm-4 7s.1-.9.8-1.8l.2-.2V8h-1.9l-.6.6C12.9 9.3 11 12 11 16v4h6c1.1 0 2-.9 2-2v-6h-4z" id="path6"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-rtl.png
new file mode 100644
index 00000000..e305696d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/quotesAdd-rtl.svg
new file mode 100644
index 00000000..9aed41d3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.1V6c1.3.2 1.9.2 3.3.8.8.5 1.6 1.1 2.2 1.8zM5 5V1h2v4h4v2H7v4H5V7H1V5zm4 7s-.1-.9-.8-1.8L8 10V8h1.9l.6.6c.6.7 2.5 3.4 2.5 7.4v4H7c-1.1 0-2-.9-2-2v-6h4z" id="path6"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/redirect-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/redirect-ltr.png
new file mode 100644
index 00000000..18ceb359
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/redirect-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/redirect-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/redirect-ltr.svg
new file mode 100644
index 00000000..be25d436
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-.4H4.4v16.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-.6H6.4V16h5.4s-.4-1.5-.4-2h-5v-1h9v1c.4.1 1.1.1 1.5.1.4 0 .7 0 1.1-.1V3.5c.1-.5-.1-.9-.3-1.1zM12.5 4h3v4.5h-3V4zM6.4 4h4v1.6h-4V4zm0 3h4v1.5h-4V7zm0 3h9v1.5h-9V10zm12.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/apex/images/icons/redirect-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/redirect-rtl.png
new file mode 100644
index 00000000..dc9b0e63
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/redirect-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/redirect-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/redirect-rtl.svg
new file mode 100644
index 00000000..a41d178f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.7H7.8c.6-.2 1.2-.5 1.9-1 .4-.3.8-.6 1.2-1l.5-.6h6.2V16h-5.4s.4-1.5.4-2h5v-1h-9v1c-.4.1-1.1.1-1.5.1-.4 0-.7 0-1.1-.1V3.5c-.1-.5.1-.9.3-1.1zM11.5 4h-3v4.5h3V4zm6.1 0h-4v1.6h4V4zm0 3h-4v1.5h4V7zm0 3h-9v1.5h9V10z" id="path3266"/>
+ <path d="M4.9 13.1L0 16.9l4.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/apex/images/icons/regular-expression.png b/resources/lib/oojs-ui/themes/apex/images/icons/regular-expression.png
new file mode 100644
index 00000000..00ace192
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/regular-expression.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/regular-expression.svg b/resources/lib/oojs-ui/themes/apex/images/icons/regular-expression.svg
new file mode 100644
index 00000000..844013d3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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="M3 12.045c0-.99.15-1.915.45-2.777.306-.862.743-1.618 1.314-2.268H6.23c-.552.72-.968 1.512-1.25 2.374-.28.862-.42 1.75-.42 2.66 0 .915.142 1.8.427 2.654.29.85.7 1.622 1.23 2.312h-1.45c-.575-.635-1.013-1.376-1.314-2.223-.3-.847-.45-1.758-.45-2.732"/>
+ <path id="dot" d="M10 16c0 .552-.448 1-1 1s-1-.448-1-1 .448-1 1-1 1 .448 1 1z"/>
+ <path id="star" d="M14.25 7.013l-.24 2.156 2.187-.61.193 1.474-1.992.14 1.307 1.74-1.33.71-.914-1.834-.8 1.823-1.382-.697 1.295-1.74-1.98-.152.23-1.465 2.14.61-.24-2.158h1.534"/>
+ <path id="right-bracket" d="M21 12.045c0 .982-.152 1.896-.457 2.744-.3.843-.737 1.58-1.307 2.21h-1.453c.527-.69.936-1.458 1.225-2.31.29-.854.434-1.74.434-2.66 0-.91-.14-1.796-.422-2.66-.28-.86-.697-1.653-1.248-2.373h1.465c.574.652 1.012 1.412 1.313 2.28.3.86.45 1.782.45 2.764"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/remove.png b/resources/lib/oojs-ui/themes/apex/images/icons/remove.png
new file mode 100644
index 00000000..9dc34b8a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/remove.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/remove.svg b/resources/lib/oojs-ui/themes/apex/images/icons/remove.svg
new file mode 100644
index 00000000..ef5f97b0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/remove.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="remove">
+ <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0H9v6h1v-6zm4 0h-1v6h1v-6zm0-4V5H9v1H6v3h1v7.966l1 1.03v-.073V18h6.984l.016-.018v.015l1-1.03V9h1V6h-3zm1 11H8V9h7v8zm1-9H7V7h9v1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/search.png b/resources/lib/oojs-ui/themes/apex/images/icons/search.png
new file mode 100644
index 00000000..d6e3e8e0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/search.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/search.svg b/resources/lib/oojs-ui/themes/apex/images/icons/search.svg
new file mode 100644
index 00000000..137150b3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/search.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="search" d="M16.02 15.96l-2.373-2.375-.17-.1c.404-.565.644-1.26.644-2.008C14.12 9.557 12.567 8 10.648 8 8.727 8 7.17 9.557 7.17 11.478c0 1.92 1.556 3.477 3.477 3.477.75 0 1.442-.24 2.01-.643l.098.17 2.375 2.373c.19.19.542.143.79-.104s.292-.6.103-.79zm-5.376-2.27c-1.22 0-2.213-.99-2.213-2.213 0-1.22.996-2.213 2.217-2.213 1.222 0 2.213.992 2.213 2.213 0 1.222-.993 2.213-2.214 2.213z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/secure-link.png b/resources/lib/oojs-ui/themes/apex/images/icons/secure-link.png
new file mode 100644
index 00000000..a2eba488
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/secure-link.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/secure-link.svg b/resources/lib/oojs-ui/themes/apex/images/icons/secure-link.svg
new file mode 100644
index 00000000..e064672f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.02v-.997c0-.057.003-1.41-.833-2.255-.434-.438-.998-.66-1.68-.66s-1.244.222-1.677.66c-.837.846-.833 2.198-.832 2.25V5H3c-.553 0-1 .447-1 1v3c0 .553.447 1 1 1h5c.553 0 1-.447 1-1V6c0-.553-.447-1-1-1zM3.998 5V3.993c0-.01.005-1 .543-1.543.486-.485 1.45-.487 1.936-.002.544.546.546 1.536.546 1.55V5H3.998z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/settings.png b/resources/lib/oojs-ui/themes/apex/images/icons/settings.png
new file mode 100644
index 00000000..dd2706b4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/settings.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/settings.svg b/resources/lib/oojs-ui/themes/apex/images/icons/settings.svg
new file mode 100644
index 00000000..37997674
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/settings.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="settings">
+ <path id="gear" d="M3 4h3v2H3zm9 0h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1H8c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1zm-5 8h9v2H3zm15 0h3v2h-3zm-4-1h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2H3zm12 0h6v2h-6zm-4-1h2c.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/apex/images/icons/smaller-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/smaller-ltr.png
new file mode 100644
index 00000000..7181e6d4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/smaller-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/smaller-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/smaller-ltr.svg
new file mode 100644
index 00000000..82d16af9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/smaller-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/smaller-rtl.png
new file mode 100644
index 00000000..cc539f0e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/smaller-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/smaller-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/smaller-rtl.svg
new file mode 100644
index 00000000..7466f48b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/specialCharacter.png b/resources/lib/oojs-ui/themes/apex/images/icons/specialCharacter.png
new file mode 100644
index 00000000..7f658819
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/specialCharacter.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/specialCharacter.svg b/resources/lib/oojs-ui/themes/apex/images/icons/specialCharacter.svg
new file mode 100644
index 00000000..dbf6ed5a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-.31.366-.53.808-.66 1.327-.124.513-.19 1.08-.19 1.7 0 .512.06 1 .176 1.46.122.46.31.87.568 1.23.63.862 1.156 1.138 2.012 1.362L11 18H6v-3h.604l.53 1.353.395.053.6.044.75.035.458.01H10l-.09-.895c-.63-.094-.812-.268-1.337-.522-.525-.26-.98-.59-1.365-.99-.38-.402-.675-.868-.89-1.4-.213-.536-.32-1.13-.32-1.778 0-.82.13-1.537.394-2.15.27-.62.656-1.133 1.163-1.54.507-.407 1.133-.71 1.878-.912.745-.206 1.6-.31 2.565-.31.96 0 1.81.103 2.556.31.75.2 1.38.504 1.887.912.51.407.896.92 1.158 1.54.27.614.403 1.33.403 2.15 0 .65-.107 1.242-.32 1.78-.215.53-.514.996-.9 1.397-.38.4-.83.732-1.355.99-.525.255-.707.43-1.336.523l-.093.894h.66l.447-.01.75-.034.606-.044.4-.053.533-1.354H18v3h-5l.246-3.04c1.066-.11 1.337-.695 2.002-1.362.263-.36.452-.77.568-1.23.122-.46.183-.947.183-1.46 0-.62-.067-1.186-.195-1.7-.128-.52-.348-.96-.66-1.326-.31-.372-.73-.66-1.255-.867-.524-.206-1.1-.31-1.893-.31"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/star.png b/resources/lib/oojs-ui/themes/apex/images/icons/star.png
new file mode 100644
index 00000000..046bbf7e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/star.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/star.svg b/resources/lib/oojs-ui/themes/apex/images/icons/star.svg
new file mode 100644
index 00000000..54ba77ad
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-.5L12 7.4M12 4L9.2 9.6l-6.2.9 4.5 4.4L6.4 21l5.6-3 5.5 3-1-6.2 4.5-4.4-6.3-.9L12 4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-a.png b/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-a.png
new file mode 100644
index 00000000..cab7a980
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-a.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-a.svg b/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-a.svg
new file mode 100644
index 00000000..070d7853
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 11h12v1H6v-1z"/>
+ <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>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-s.png b/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-s.png
new file mode 100644
index 00000000..1bcb55bd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-s.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-s.svg b/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-s.svg
new file mode 100644
index 00000000..46092a6b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 12h12v1H6v-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 .89.22 1.602.72 2.13.497.528 1.278.91 2.31 1.14l.813.182v-.03c.656.147 1.128.375 1.375.63.252.256.375.607.375 1.11 0 .573-.172.97-.53 1.26-.36.29-.895.45-1.626.45-.473 0-.965-.074-1.465-.24-.502-.166-1.03-.417-1.562-.75l-.374-.238v2.158l.155.062c.58.237 1.144.417 1.69.54.548.12 1.07.18 1.56.18 1.287 0 2.298-.293 3-.9.71-.605 1.063-1.486 1.063-2.608 0-.943-.256-1.726-.78-2.312-.522-.592-1.306-1-2.345-1.23l-.812-.18c-.715-.148-1.203-.352-1.405-.54-.205-.202-.312-.484-.312-.934 0-.533.162-.9.5-1.17.342-.27.836-.42 1.53-.42.396 0 .82.052 1.25.18.434.128.91.334 1.407.6l.374.18V6.63s-1.188-.383-1.688-.48c-.5-.097-.984-.15-1.468-.15z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-y.png b/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-y.png
new file mode 100644
index 00000000..5b1c1fd5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-y.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-y.svg b/resources/lib/oojs-ui/themes/apex/images/icons/strikethrough-y.svg
new file mode 100644
index 00000000..2fdbc871
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 11h12v1H6v-1z"/>
+ <path id="a" d="M7 6h1.724l3.288 4.935L15.276 6H17l-4.194 6.285V18h-1.612v-5.715L7 6"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/subscript-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/subscript-ltr.png
new file mode 100644
index 00000000..f8b8766c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/subscript-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/subscript-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/subscript-ltr.svg
new file mode 100644
index 00000000..fbb0c3c3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/subscript-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/subscript-rtl.png
new file mode 100644
index 00000000..f01e11db
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/subscript-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/subscript-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/subscript-rtl.svg
new file mode 100644
index 00000000..91a71ecc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/superscript-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/superscript-ltr.png
new file mode 100644
index 00000000..69fe6e7a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/superscript-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/superscript-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/superscript-ltr.svg
new file mode 100644
index 00000000..45abfda2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/superscript-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/superscript-rtl.png
new file mode 100644
index 00000000..eac3d1d7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/superscript-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/superscript-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/superscript-rtl.svg
new file mode 100644
index 00000000..33b5814b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/table-caption.png b/resources/lib/oojs-ui/themes/apex/images/icons/table-caption.png
new file mode 100644
index 00000000..1389d3d8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table-caption.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table-caption.svg b/resources/lib/oojs-ui/themes/apex/images/icons/table-caption.svg
new file mode 100644
index 00000000..6b7edc6f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/table-insert-column-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-ltr.png
new file mode 100644
index 00000000..dfd5e512
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-ltr.svg
new file mode 100644
index 00000000..a67ed201
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-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="table-insert-column-ltr">
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M5 5h2v14H5z" id="column"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-rtl.png
new file mode 100644
index 00000000..1354a882
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-rtl.svg
new file mode 100644
index 00000000..dee782e9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-column-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="table-insert-column-rtl">
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M17 5h2v14h-2z" id="column"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-after.png b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-after.png
new file mode 100644
index 00000000..3d8091e8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-after.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-after.svg b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-after.svg
new file mode 100644
index 00000000..ad9d86db
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-after.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-row-after">
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M5 17h14v2H5z" id="row"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-before.png b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-before.png
new file mode 100644
index 00000000..e357f90e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-before.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-before.svg b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-before.svg
new file mode 100644
index 00000000..e9dfe048
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table-insert-row-before.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-row-before">
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M5 5h14v2H5z" id="row"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table-merge-cells.png b/resources/lib/oojs-ui/themes/apex/images/icons/table-merge-cells.png
new file mode 100644
index 00000000..202a1209
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table-merge-cells.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table-merge-cells.svg b/resources/lib/oojs-ui/themes/apex/images/icons/table-merge-cells.svg
new file mode 100644
index 00000000..3ffb9e5e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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="M4 7v9h7v-3l-1 .834V15H5V8h5v1.167L11 10V7z"/>
+ <path id="arrow" d="M8 9v2H6v1h2v2l3-2.5z"/>
+ </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/apex/images/icons/table.png b/resources/lib/oojs-ui/themes/apex/images/icons/table.png
new file mode 100644
index 00000000..2eedd1e3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/table.svg b/resources/lib/oojs-ui/themes/apex/images/icons/table.svg
new file mode 100644
index 00000000..b5733fba
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/table.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="table-insert">
+ <path id="table" d="M4 6v11h15V6zm1 3h6v3H5zm7 0h6v3h-6zm-7 4h6v3H5zm7 0h6v3h-6z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/tag.png b/resources/lib/oojs-ui/themes/apex/images/icons/tag.png
new file mode 100644
index 00000000..3bfbd0b6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/tag.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/tag.svg b/resources/lib/oojs-ui/themes/apex/images/icons/tag.svg
new file mode 100644
index 00000000..5265e04b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/tag.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="tag">
+ <path d="M18.748 11.717c.39.39.39 1.025 0 1.414l-4.95 4.95c-.388.39-1.024.39-1.413 0l-6.01-6.01c-.39-.385-.707-1.153-.707-1.703V6c0-.55.45-1 1-1h4.363c.55 0 1.32.318 1.71.707l6.01 6.01zM8.104 7.457c-.58.575-.578 1.513 0 2.092.577.573 1.515.573 2.094 0 .576-.58.576-1.52 0-2.098-.58-.576-1.518-.577-2.094 0z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-ltr.png
new file mode 100644
index 00000000..dd52d120
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-ltr.svg
new file mode 100644
index 00000000..13b1fc72
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-4V2h-2v4h-4v2h4v4h2V8h4z"/>
+ </g>
+ <path d="M19 13v7H3c-1.1 0-2-.9-2-2V7h12V6H0v12c0 1.7 1.3 3 3 3h17v-8h-1z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-rtl.png
new file mode 100644
index 00000000..08b1613c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/templateAdd-rtl.svg
new file mode 100644
index 00000000..d44c3a41
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 6h4V2h2v4h4v2H6v4H4V8H0z" id="path692"/>
+ </g>
+ <path d="M5 13v7h16c1.1 0 2-.9 2-2V7H11V6h13v12c0 1.7-1.3 3-3 3H4v-8h1z" id="path694"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/text-dir-lefttoright.png b/resources/lib/oojs-ui/themes/apex/images/icons/text-dir-lefttoright.png
new file mode 100644
index 00000000..ffd190a1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/text-dir-lefttoright.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/text-dir-lefttoright.svg b/resources/lib/oojs-ui/themes/apex/images/icons/text-dir-lefttoright.svg
new file mode 100644
index 00000000..7dbff919
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 7H5V6h2l.47.5L8 6h2v1H8v10h2v1H8l-.5-.53L7 18H5v-1h2zm6.976 9v-2H11v-4h2.976V8.044L20 12.022z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/text-dir-righttoleft.png b/resources/lib/oojs-ui/themes/apex/images/icons/text-dir-righttoleft.png
new file mode 100644
index 00000000..214f8d14
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/text-dir-righttoleft.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/text-dir-righttoleft.svg b/resources/lib/oojs-ui/themes/apex/images/icons/text-dir-righttoleft.svg
new file mode 100644
index 00000000..76933a62
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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-.47-.5-.53.5h-2v-1h2V7h-2V6h2l.5.53L17 6h2v1h-2zm-6.976-9v2H13v4h-2.976v1.956L4 11.978z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/text-style.png b/resources/lib/oojs-ui/themes/apex/images/icons/text-style.png
new file mode 100644
index 00000000..a2f48bea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/text-style.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/text-style.svg b/resources/lib/oojs-ui/themes/apex/images/icons/text-style.svg
new file mode 100644
index 00000000..466672eb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.79l-1.14-12h-2.79L6 18h2.79l2.038-3h4.183l.29 3zm-3.11-5L14.5 9.6l.323 3.4H12.19z"/>
+ <path id="underline" d="M6 19h12v1H6v-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/translation-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/translation-ltr.png
new file mode 100644
index 00000000..10254613
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/translation-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/translation-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/translation-ltr.svg
new file mode 100644
index 00000000..8954a21a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.1C9.3 11 8.4 8.8 8.1 8h4.7l.7-2H8V3H6v3H1v2h5c-.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.2L18 6h-3l-4.7 14h2.2zm4-12l2 6h-4l2-6z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/translation-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/translation-rtl.png
new file mode 100644
index 00000000..38066d69
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/translation-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/translation-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/translation-rtl.svg
new file mode 100644
index 00000000..44ba9719
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.7L10 6h5.5V3h2v3h5v2h-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.2zM11 20l-1.3-4H4.4l-1.3 4H.9L5.5 6h3l4.7 14H11zM7 8l-2 6h4L7 8z" id="path704"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/trash.png b/resources/lib/oojs-ui/themes/apex/images/icons/trash.png
new file mode 100644
index 00000000..dfee886c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/trash.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/trash.svg b/resources/lib/oojs-ui/themes/apex/images/icons/trash.svg
new file mode 100644
index 00000000..76502dce
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 2H6zm1 1h10l-1 11H8z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-ltr.png
new file mode 100644
index 00000000..594836ec
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-ltr.svg
new file mode 100644
index 00000000..071bd325
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.5L5 5 4 6l3 3 1 11h8l.2-1.8 3.3 3.3zM17 9h-6l5.5 5.5zm1-1c0-1.1-.9-2-2-2h-2l-1-1h-2l-1 1H8l2 2h8z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-rtl.png
new file mode 100644
index 00000000..182e56d9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/trashUndo-rtl.svg
new file mode 100644
index 00000000..69c17b46
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.5L19.5 5l1 1-3 3-1 11h-8l-.2-1.8L5 21.5zM7.5 9h6L8 14.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/apex/images/icons/unLock-ltr.png b/resources/lib/oojs-ui/themes/apex/images/icons/unLock-ltr.png
new file mode 100644
index 00000000..c7fce470
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/unLock-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/unLock-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/icons/unLock-ltr.svg
new file mode 100644
index 00000000..f443f846
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/unLock-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="unLock">
+ <path d="M8 6c-2.21 0-4 1.79-4 4v1h2v-1c0-1.105.895-2 2-2s2 .895 2 2v1H9v7h10v-7h-7v-1c0-2.21-1.79-4-4-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/unLock-rtl.png b/resources/lib/oojs-ui/themes/apex/images/icons/unLock-rtl.png
new file mode 100644
index 00000000..63ec5cbf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/unLock-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/unLock-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/icons/unLock-rtl.svg
new file mode 100644
index 00000000..1aabf8bd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/unLock-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="unLock">
+ <path d="M15 6c2.21 0 4 1.79 4 4v1h-2v-1c0-1.105-.895-2-2-2s-2 .895-2 2v1h1v7H4v-7h7v-1c0-2.21 1.79-4 4-4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/unStar.png b/resources/lib/oojs-ui/themes/apex/images/icons/unStar.png
new file mode 100644
index 00000000..bdb1c4fe
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/unStar.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/unStar.svg b/resources/lib/oojs-ui/themes/apex/images/icons/unStar.svg
new file mode 100644
index 00000000..724d1901
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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/apex/images/icons/underline-a.png b/resources/lib/oojs-ui/themes/apex/images/icons/underline-a.png
new file mode 100644
index 00000000..f4add0a0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/underline-a.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/underline-a.svg b/resources/lib/oojs-ui/themes/apex/images/icons/underline-a.svg
new file mode 100644
index 00000000..1ddae104
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 16H16.5L13.037 6H10.96L7.5 16h2.077l.627-2h3.604l.616 2zm-3.92-3.623L12 7.997l1.51 4.38h-3z"/>
+ <path id="underline" d="M7 17h10v1H7v-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/underline-u.png b/resources/lib/oojs-ui/themes/apex/images/icons/underline-u.png
new file mode 100644
index 00000000..2504e668
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/underline-u.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/underline-u.svg b/resources/lib/oojs-ui/themes/apex/images/icons/underline-u.svg
new file mode 100644
index 00000000..f5aaf5d6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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.96c-.104 1.706.695 2 2 2.04 1.777.062 2.002-.88 2-2.04V6h2v6.123c0 1.28-.338 2.245-1.016 2.898-.672.655-1.666.98-2.98.98-1.32 0-2.32-.323-2.996-.98C8.336 14.37 8 13.406 8 12.127V6"/>
+ <path id="underline" d="M7 17h10v1H7v-1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/upTriangle.png b/resources/lib/oojs-ui/themes/apex/images/icons/upTriangle.png
new file mode 100644
index 00000000..1b655891
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/upTriangle.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/upTriangle.svg b/resources/lib/oojs-ui/themes/apex/images/icons/upTriangle.svg
new file mode 100644
index 00000000..9f0efc59
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 10H4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/wikiText.png b/resources/lib/oojs-ui/themes/apex/images/icons/wikiText.png
new file mode 100644
index 00000000..4b15161c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/wikiText.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/wikiText.svg b/resources/lib/oojs-ui/themes/apex/images/icons/wikiText.svg
new file mode 100644
index 00000000..ded0fe1a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/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 5h4v2H4v10h2v2H2z"/>
+ </g>
+ <g>
+ <path d="M7 5h4v2H9v10h2v2H7z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/window.png b/resources/lib/oojs-ui/themes/apex/images/icons/window.png
new file mode 100644
index 00000000..db726a19
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/window.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/icons/window.svg b/resources/lib/oojs-ui/themes/apex/images/icons/window.svg
new file mode 100644
index 00000000..093c8228
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/icons/window.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="window">
+ <path id="title" d="M7 10h10v1H7z"/>
+ <path id="frame" d="M16 19H8c-2.206 0-4-1.794-4-4V9c0-2.206 1.794-4 4-4h8c2.206 0 4 1.794 4 4v6c0 2.206-1.794 4-4 4zM8 7c-1.103 0-2 .897-2 2v6c0 1.103.897 2 2 2h8c1.103 0 2-.897 2-2V9c0-1.103-.897-2-2-2H8z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/alert.png b/resources/lib/oojs-ui/themes/apex/images/indicators/alert.png
new file mode 100644
index 00000000..5bf08278
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/alert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/alert.svg b/resources/lib/oojs-ui/themes/apex/images/indicators/alert.svg
new file mode 100644
index 00000000..868bcc96
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/alert.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="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 6zM5 7h2V2H5zm0 3h2V8H5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-down.png b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-down.png
new file mode 100644
index 00000000..65747259
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-down.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-down.svg b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-down.svg
new file mode 100644
index 00000000..5ce25ba0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-down.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="down">
+ <path id="arrow" d="M2 3l3.5 6L9 3z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-ltr.png b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-ltr.png
new file mode 100644
index 00000000..7c84397c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-ltr.svg
new file mode 100644
index 00000000..e0f13e6d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-ltr.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="ltr">
+ <path id="arrow" d="M3 9V2l6 3.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-rtl.png b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-rtl.png
new file mode 100644
index 00000000..5bf90642
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-rtl.svg
new file mode 100644
index 00000000..c88c364b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-rtl.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="rtl">
+ <path id="arrow" d="M3 5.5L9 9V2z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-up.png b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-up.png
new file mode 100644
index 00000000..1a05ade6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-up.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-up.svg b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-up.svg
new file mode 100644
index 00000000..7a250f58
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/arrow-up.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="up">
+ <path id="arrow" d="M5.5 2L2 8h7z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/clear.png b/resources/lib/oojs-ui/themes/apex/images/indicators/clear.png
new file mode 100644
index 00000000..5db444c5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/clear.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/clear.svg b/resources/lib/oojs-ui/themes/apex/images/indicators/clear.svg
new file mode 100644
index 00000000..3c010c10
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/clear.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="clear">
+ <path id="circle-with-cross" d="M6 0C2.7 0 0 2.7 0 6s2.7 6 6 6 6-2.7 6-6-2.7-6-6-6zM3.5 2.5L6 5l2.5-2.5 1 1L7 6l2.5 2.5-1 1L6 7 3.5 9.5l-1-1L5 6 2.5 3.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/required.png b/resources/lib/oojs-ui/themes/apex/images/indicators/required.png
new file mode 100644
index 00000000..45eb03b6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/required.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/required.svg b/resources/lib/oojs-ui/themes/apex/images/indicators/required.svg
new file mode 100644
index 00000000..d1e0cba6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/required.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="required">
+ <path d="M5 1h2v10H5zm4.83 1.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/apex/images/indicators/search-ltr.png b/resources/lib/oojs-ui/themes/apex/images/indicators/search-ltr.png
new file mode 100644
index 00000000..2718a9b0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/search-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/search-ltr.svg b/resources/lib/oojs-ui/themes/apex/images/indicators/search-ltr.svg
new file mode 100644
index 00000000..9b3c1997
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/search-ltr.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="search">
+ <path id="path3051" d="M10.37 9.474L7.994 7.1l-.17-.1c.404-.566.644-1.26.644-2.01-.002-1.92-1.56-3.476-3.478-3.476-1.92 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.75 0 1.442-.24 2.01-.647l.098.17 2.375 2.373c.19.188.543.142.79-.105s.293-.6.104-.79zm-5.38-2.27c-1.22 0-2.213-.99-2.213-2.213 0-1.22.99-2.21 2.212-2.21 1.22 0 2.21.99 2.21 2.214s-.99 2.213-2.21 2.213z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/search-rtl.png b/resources/lib/oojs-ui/themes/apex/images/indicators/search-rtl.png
new file mode 100644
index 00000000..b7a8d221
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/search-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/indicators/search-rtl.svg b/resources/lib/oojs-ui/themes/apex/images/indicators/search-rtl.svg
new file mode 100644
index 00000000..3201301e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/indicators/search-rtl.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="search">
+ <path id="path3051" d="M1.63 9.474L4.006 7.1l.17-.1c-.404-.566-.644-1.26-.644-2.01.002-1.92 1.56-3.476 3.478-3.476 1.92 0 3.478 1.557 3.478 3.478 0 1.92-1.557 3.477-3.478 3.477-.75 0-1.442-.24-2.01-.647l-.098.17-2.375 2.373c-.19.188-.543.142-.79-.105s-.293-.6-.104-.79zm5.378-2.27c1.22 0 2.213-.99 2.213-2.213 0-1.22-.99-2.21-2.21-2.21S4.8 3.77 4.8 4.995 5.79 7.207 7.01 7.207z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/textures/pending.gif b/resources/lib/oojs-ui/themes/apex/images/textures/pending.gif
new file mode 100644
index 00000000..1194eed2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/textures/pending.gif
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/textures/transparency.png b/resources/lib/oojs-ui/themes/apex/images/textures/transparency.png
new file mode 100644
index 00000000..1843f27d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/textures/transparency.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/images/textures/transparency.svg b/resources/lib/oojs-ui/themes/apex/images/textures/transparency.svg
new file mode 100644
index 00000000..cadec2a6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/textures/transparency.svg
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+ <g id="transparency">
+ <path d="M0 0h8v8H0zm8 8h8v8H8z" fill="#ccc"/>
+ <path d="M8 0h8v8H8zM0 8h8v8H0z" fill="#fff"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/apex/images/toolbar-shadow.png b/resources/lib/oojs-ui/themes/apex/images/toolbar-shadow.png
new file mode 100644
index 00000000..97e8d13d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/images/toolbar-shadow.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/apex/indicators.json b/resources/lib/oojs-ui/themes/apex/indicators.json
new file mode 100644
index 00000000..9a9afa8b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/indicators.json
@@ -0,0 +1,23 @@
+{
+ "prefix": "oo-ui-indicator",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "alert": { "file": "images/indicators/alert.svg" },
+ "clear": { "file": "images/indicators/clear.svg" },
+ "up": { "file": "images/indicators/arrow-up.svg" },
+ "down": { "file": "images/indicators/arrow-down.svg" },
+ "next": { "file": {
+ "ltr": "images/indicators/arrow-ltr.svg",
+ "rtl": "images/indicators/arrow-rtl.svg"
+ } },
+ "previous": { "file": {
+ "ltr": "images/indicators/arrow-rtl.svg",
+ "rtl": "images/indicators/arrow-ltr.svg"
+ } },
+ "required": { "file": "images/indicators/required.svg" },
+ "search": { "file": {
+ "ltr": "images/indicators/search-ltr.svg",
+ "rtl": "images/indicators/search-rtl.svg"
+ } }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/apex/textures.json b/resources/lib/oojs-ui/themes/apex/textures.json
new file mode 100644
index 00000000..e90730ab
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/apex/textures.json
@@ -0,0 +1,8 @@
+{
+ "prefix": "oo-ui-texture",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "pending": { "file": "images/textures/pending.gif" },
+ "transparency": { "file": "images/textures/transparency.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-accessibility.json b/resources/lib/oojs-ui/themes/mediawiki/icons-accessibility.json
new file mode 100644
index 00000000..ee1d0a5c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-accessibility.json
@@ -0,0 +1,19 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "bright": { "file": "images/icons/bright.svg" },
+ "halfBright": { "file": "images/icons/halfBright.svg" },
+ "notBright": { "file": "images/icons/notBright.svg" },
+ "moon": { "file": "images/icons/moon.svg" },
+ "largerText": { "file": {
+ "ltr": "images/icons/largerText-ltr.svg",
+ "rtl": "images/icons/largerText-rtl.svg"
+ } },
+ "smallerText": { "file": {
+ "ltr": "images/icons/smallerText-ltr.svg",
+ "rtl": "images/icons/smallerText-rtl.svg"
+ } },
+ "visionSimulator": { "file": "images/icons/visionSimulator.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-alerts.json b/resources/lib/oojs-ui/themes/mediawiki/icons-alerts.json
new file mode 100644
index 00000000..701166a0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-alerts.json
@@ -0,0 +1,39 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "bell": { "file": "images/icons/bell.svg" },
+ "bellOn": { "file": {
+ "ltr": "images/icons/bellOn-ltr.svg",
+ "rtl": "images/icons/bellOn-rtl.svg"
+ } },
+ "eye": { "file": "images/icons/eye.svg" },
+ "eyeClosed": { "file": "images/icons/eyeClosed.svg" },
+ "message": { "file": {
+ "ltr": "images/icons/message-ltr.svg",
+ "rtl": "images/icons/message-rtl.svg"
+ } },
+ "signature": { "file": {
+ "ltr": "images/icons/signature-ltr.svg",
+ "rtl": "images/icons/signature-rtl.svg"
+ } },
+ "speechBubble": { "file": {
+ "ltr": "images/icons/speechBubble-ltr.svg",
+ "rtl": "images/icons/speechBubble-rtl.svg"
+ } },
+ "speechBubbleAdd": { "file": {
+ "ltr": "images/icons/speechBubbleAdd-ltr.svg",
+ "rtl": "images/icons/speechBubbleAdd-rtl.svg"
+ } },
+ "speechBubbles": { "file": {
+ "ltr": "images/icons/speechBubbles-ltr.svg",
+ "rtl": "images/icons/speechBubbles-rtl.svg"
+ } }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-content.json b/resources/lib/oojs-ui/themes/mediawiki/icons-content.json
new file mode 100644
index 00000000..18c8dd5e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-content.json
@@ -0,0 +1,56 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "article": { "file": {
+ "ltr": "images/icons/article-ltr.svg",
+ "rtl": "images/icons/article-rtl.svg"
+ } },
+ "articleCheck": { "file": {
+ "ltr": "images/icons/articleCheck-ltr.svg",
+ "rtl": "images/icons/articleCheck-rtl.svg"
+ } },
+ "articleSearch": { "file": {
+ "ltr": "images/icons/articleSearch-ltr.svg",
+ "rtl": "images/icons/articleSearch-rtl.svg"
+ } },
+ "book": { "file": {
+ "ltr": "images/icons/book-ltr.svg",
+ "rtl": "images/icons/book-rtl.svg"
+ } },
+ "citeArticle": { "file": {
+ "ltr": "images/icons/citeArticle-ltr.svg",
+ "rtl": "images/icons/citeArticle-rtl.svg"
+ } },
+ "die": { "file": {
+ "ltr": "images/icons/die-ltr.svg",
+ "rtl": "images/icons/die-rtl.svg"
+ } },
+ "download": { "file": {
+ "ltr": "images/icons/download-ltr.svg",
+ "rtl": "images/icons/download-rtl.svg"
+ } },
+ "folderPlaceholder": { "file": {
+ "ltr": "images/icons/folderPlaceholder-ltr.svg",
+ "rtl": "images/icons/folderPlaceholder-rtl.svg"
+ } },
+ "journal": { "file": {
+ "ltr": "images/icons/journal-ltr.svg",
+ "rtl": "images/icons/journal-rtl.svg"
+ } },
+ "newspaper": { "file": {
+ "ltr": "images/icons/newspaper-ltr.svg",
+ "rtl": "images/icons/newspaper-rtl.svg"
+ } },
+ "upload": { "file": {
+ "ltr": "images/icons/upload-ltr.svg",
+ "rtl": "images/icons/upload-rtl.svg"
+ } }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-editing-advanced.json b/resources/lib/oojs-ui/themes/mediawiki/icons-editing-advanced.json
new file mode 100644
index 00000000..ef368c23
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-editing-advanced.json
@@ -0,0 +1,85 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "alignCentre": { "file": "images/icons/align-center.svg" },
+ "alignLeft": { "file": "images/icons/align-float-left.svg" },
+ "alignRight": { "file": "images/icons/align-float-right.svg" },
+ "calendar": { "file": {
+ "ltr": "images/icons/calendar-ltr.svg",
+ "rtl": "images/icons/calendar-rtl.svg"
+ } },
+ "find": { "file": {
+ "ltr": "images/icons/find-ltr.svg",
+ "rtl": "images/icons/find-rtl.svg"
+ } },
+ "insert": { "file": "images/icons/insert.svg" },
+ "layout": { "file": {
+ "ltr": "images/icons/layout-ltr.svg",
+ "rtl": "images/icons/layout-rtl.svg"
+ } },
+ "newline": { "file": {
+ "ltr": "images/icons/newline-ltr.svg",
+ "rtl": "images/icons/newline-rtl.svg"
+ } },
+ "redirect": { "file": {
+ "ltr": "images/icons/redirect-ltr.svg",
+ "rtl": "images/icons/redirect-rtl.svg"
+ } },
+ "noWikiText": { "file": {
+ "ltr": "images/icons/noWikiText-ltr.svg",
+ "rtl": "images/icons/noWikiText-rtl.svg"
+ } },
+ "outline": { "file": {
+ "ltr": "images/icons/outline-ltr.svg",
+ "rtl": "images/icons/outline-rtl.svg"
+ } },
+ "puzzle": { "file": {
+ "ltr": "images/icons/puzzle-ltr.svg",
+ "rtl": "images/icons/puzzle-rtl.svg"
+ } },
+ "quotes": { "file": {
+ "ltr": "images/icons/quotes-ltr.svg",
+ "rtl": "images/icons/quotes-rtl.svg"
+ } },
+ "quotesAdd": { "file": {
+ "ltr": "images/icons/quotesAdd-ltr.svg",
+ "rtl": "images/icons/quotesAdd-rtl.svg"
+ } },
+ "redirect": { "file": {
+ "ltr": "images/icons/redirect-ltr.svg",
+ "rtl": "images/icons/redirect-rtl.svg"
+ } },
+ "searchCaseSensitive": { "file": "images/icons/case-sensitive.svg" },
+ "searchRegularExpression": { "file": "images/icons/regular-expression.svg" },
+ "specialCharacter": { "file": "images/icons/specialCharacter.svg" },
+ "table": { "file": "images/icons/table.svg" },
+ "tableAddColumnAfter": { "file": {
+ "ltr": "images/icons/table-insert-column-rtl.svg",
+ "rtl": "images/icons/table-insert-column-ltr.svg"
+ } },
+ "tableAddColumnBefore": { "file": {
+ "ltr": "images/icons/table-insert-column-ltr.svg",
+ "rtl": "images/icons/table-insert-column-rtl.svg"
+ } },
+ "tableAddRowAfter": { "file": "images/icons/table-insert-row-after.svg" },
+ "tableAddRowBefore": { "file": "images/icons/table-insert-row-before.svg" },
+ "tableCaption": { "file": "images/icons/table-caption.svg" },
+ "tableMergeCells": { "file": "images/icons/table-merge-cells.svg" },
+ "templateAdd": { "file": {
+ "ltr": "images/icons/templateAdd-ltr.svg",
+ "rtl": "images/icons/templateAdd-rtl.svg"
+ } },
+ "translation": { "file": {
+ "ltr": "images/icons/translation-ltr.svg",
+ "rtl": "images/icons/translation-rtl.svg"
+ } },
+ "wikiText": { "file": "images/icons/wikiText.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-editing-core.json b/resources/lib/oojs-ui/themes/mediawiki/icons-editing-core.json
new file mode 100644
index 00000000..3bacb605
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-editing-core.json
@@ -0,0 +1,45 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ },
+ "progressive": {
+ "color": "#347BFF"
+ },
+ "constructive": {
+ "color": "#00AF89"
+ },
+ "destructive": {
+ "color": "#D11D13"
+ },
+ "warning": {
+ "color": "#FF5D00"
+ }
+ },
+ "images": {
+ "edit": { "file": {
+ "ltr": "images/icons/edit-ltr.svg",
+ "rtl": "images/icons/edit-rtl.svg"
+ }, "variants": [ "progressive" ] },
+ "editLock": { "file": {
+ "ltr": "images/icons/editLock-ltr.svg",
+ "rtl": "images/icons/editLock-rtl.svg"
+ } },
+ "editUndo": { "file": {
+ "ltr": "images/icons/editUndo-ltr.svg",
+ "rtl": "images/icons/editUndo-rtl.svg"
+ } },
+ "link": { "file": {
+ "ltr": "images/icons/link-ltr.svg",
+ "rtl": "images/icons/link-rtl.svg"
+ } },
+ "linkExternal": { "file": {
+ "ltr": "images/icons/external-link-ltr.svg",
+ "rtl": "images/icons/external-link-rtl.svg"
+ } },
+ "linkSecure": { "file": "images/icons/secure-link.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-editing-list.json b/resources/lib/oojs-ui/themes/mediawiki/icons-editing-list.json
new file mode 100644
index 00000000..cfd4abc9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-editing-list.json
@@ -0,0 +1,28 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "indent": { "file": {
+ "ltr": "images/icons/indent-ltr.svg",
+ "rtl": "images/icons/indent-rtl.svg"
+ } },
+ "listBullet": { "file": {
+ "ltr": "images/icons/listBullet-ltr.svg",
+ "rtl": "images/icons/listBullet-rtl.svg"
+ } },
+ "listNumbered": { "file": {
+ "ltr": "images/icons/listNumbered-ltr.svg",
+ "rtl": "images/icons/listNumbered-rtl.svg"
+ } },
+ "outdent": { "file": {
+ "ltr": "images/icons/outdent-ltr.svg",
+ "rtl": "images/icons/outdent-rtl.svg"
+ } }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-editing-styling.json b/resources/lib/oojs-ui/themes/mediawiki/icons-editing-styling.json
new file mode 100644
index 00000000..48af33a2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-editing-styling.json
@@ -0,0 +1,78 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "bigger": { "file": {
+ "ltr": "images/icons/bigger-ltr.svg",
+ "rtl": "images/icons/bigger-rtl.svg"
+ } },
+ "smaller": { "file": {
+ "ltr": "images/icons/smaller-ltr.svg",
+ "rtl": "images/icons/smaller-rtl.svg"
+ } },
+ "subscript": { "file": {
+ "ltr": "images/icons/subscript-ltr.svg",
+ "rtl": "images/icons/subscript-rtl.svg"
+ } },
+ "superscript": { "file": {
+ "ltr": "images/icons/superscript-ltr.svg",
+ "rtl": "images/icons/superscript-rtl.svg"
+ } },
+ "bold": { "file": {
+ "default": "images/icons/bold-a.svg",
+ "lang": {
+ "ar": "images/icons/bold-arab-ain.svg",
+ "be": "images/icons/bold-cyrl-te.svg",
+ "cs,en,he,ml,pl,sco": "images/icons/bold-b.svg",
+ "da,de,hu,ksh,nn,no,sv": "images/icons/bold-f.svg",
+ "es,gl,pt": "images/icons/bold-n.svg",
+ "eu,fi": "images/icons/bold-l.svg",
+ "fa": "images/icons/bold-arab-dad.svg",
+ "fr,it": "images/icons/bold-g.svg",
+ "hy": "images/icons/bold-armn-to.svg",
+ "ka": "images/icons/bold-geor-man.svg",
+ "ky,ru": "images/icons/bold-cyrl-zhe.svg",
+ "nl": "images/icons/bold-v.svg",
+ "os": "images/icons/bold-cyrl-be.svg"
+ }
+ } },
+ "italic": { "file": {
+ "default": "images/icons/italic-a.svg",
+ "lang": {
+ "ar": "images/icons/italic-arab-meem.svg",
+ "cs,en,fr,he,ml,pl,pt,sco": "images/icons/italic-i.svg",
+ "be,da,de,fi,ky,nn,no,os,sv,ru": "images/icons/italic-k.svg",
+ "es,gl,it,nl": "images/icons/italic-c.svg",
+ "eu": "images/icons/italic-e.svg",
+ "fa": "images/icons/italic-arab-keheh-jeem.svg",
+ "hu": "images/icons/italic-d.svg",
+ "hy": "images/icons/italic-armn-sha.svg",
+ "ksh": "images/icons/italic-s.svg",
+ "ka": "images/icons/italic-geor-kan.svg"
+ }
+ } },
+ "strikethrough": { "file": {
+ "default": "images/icons/strikethrough-a.svg",
+ "lang": {
+ "en": "images/icons/strikethrough-s.svg",
+ "fi": "images/icons/strikethrough-y.svg"
+ }
+ } },
+ "underline": { "file": {
+ "default": "images/icons/underline-a.svg",
+ "lang": {
+ "en": "images/icons/underline-u.svg"
+ }
+ } },
+ "textLanguage": { "file": "images/icons/language.svg" },
+ "textDirLTR": { "file": "images/icons/text-dir-lefttoright.svg" },
+ "textDirRTL": { "file": "images/icons/text-dir-righttoleft.svg" },
+ "textStyle": { "file": "images/icons/text-style.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-interactions.json b/resources/lib/oojs-ui/themes/mediawiki/icons-interactions.json
new file mode 100644
index 00000000..02dfffa8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-interactions.json
@@ -0,0 +1,58 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "beta": { "file": "images/icons/beta.svg" },
+ "betaLaunch": { "file": "images/icons/betaLaunch.svg" },
+ "bookmark": { "file": {
+ "ltr": "images/icons/bookmark-ltr.svg",
+ "rtl": "images/icons/bookmark-rtl.svg"
+ } },
+ "browser": { "file": {
+ "ltr": "images/icons/browser-ltr.svg",
+ "rtl": "images/icons/browser-rtl.svg"
+ } },
+ "clear": { "file": "images/icons/clear.svg" },
+ "clock": { "file": "images/icons/clock.svg" },
+ "funnel": { "file": {
+ "ltr": "images/icons/funnel-ltr.svg",
+ "rtl": "images/icons/funnel-rtl.svg"
+ } },
+ "heart": { "file": "images/icons/heart.svg" },
+ "key": { "file": {
+ "ltr": "images/icons/key-ltr.svg",
+ "rtl": "images/icons/key-rtl.svg"
+ } },
+ "keyboard": { "file": {
+ "ltr": "images/icons/keyboard-ltr.svg",
+ "rtl": "images/icons/keyboard-rtl.svg"
+ } },
+ "logOut": { "file": {
+ "ltr": "images/icons/logOut-ltr.svg",
+ "rtl": "images/icons/logOut-rtl.svg"
+ } },
+ "newWindow": { "file": {
+ "ltr": "images/icons/newWindow-ltr.svg",
+ "rtl": "images/icons/newWindow-rtl.svg"
+ } },
+ "printer": { "file": {
+ "ltr": "images/icons/printer-ltr.svg",
+ "rtl": "images/icons/printer-rtl.svg"
+ } },
+ "ribbonPrize": { "file": "images/icons/ribbonPrize.svg" },
+ "sun": { "file": {
+ "ltr": "images/icons/sun-ltr.svg",
+ "rtl": "images/icons/sun-rtl.svg"
+ } },
+ "watchlist": { "file": {
+ "ltr": "images/icons/watchlist-ltr.svg",
+ "rtl": "images/icons/watchlist-rtl.svg"
+ } }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-layout.json b/resources/lib/oojs-ui/themes/mediawiki/icons-layout.json
new file mode 100644
index 00000000..c5072847
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-layout.json
@@ -0,0 +1,42 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ },
+ "progressive": {
+ "color": "#347BFF"
+ },
+ "constructive": {
+ "color": "#00AF89"
+ },
+ "destructive": {
+ "color": "#D11D13"
+ },
+ "warning": {
+ "color": "#FF5D00"
+ }
+ },
+ "images": {
+ "stripeFlow": { "file": {
+ "ltr": "images/icons/stripeFlow-ltr.svg",
+ "rtl": "images/icons/stripeFlow-rtl.svg"
+ } },
+ "stripeSideMenu": { "file": "images/icons/stripeSideMenu.svg" },
+ "stripeSummary": { "file": {
+ "ltr": "images/icons/stripeSummary-ltr.svg",
+ "rtl": "images/icons/stripeSummary-rtl.svg"
+ } },
+ "stripeToC": { "file": {
+ "ltr": "images/icons/stripeToC-ltr.svg",
+ "rtl": "images/icons/stripeToC-rtl.svg"
+ }, "variants": [ "progressive" ] },
+ "viewCompact": { "file": "images/icons/viewCompact.svg" },
+ "viewDetails": { "file": {
+ "ltr": "images/icons/viewDetails-ltr.svg",
+ "rtl": "images/icons/viewDetails-rtl.svg"
+ } }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-location.json b/resources/lib/oojs-ui/themes/mediawiki/icons-location.json
new file mode 100644
index 00000000..0ecc2e11
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-location.json
@@ -0,0 +1,25 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "map": { "file": {
+ "ltr": "images/icons/map-ltr.svg",
+ "rtl": "images/icons/map-rtl.svg"
+ } },
+ "mapPin": { "file": "images/icons/mapPin.svg" },
+ "mapPinAdd": { "file": {
+ "ltr": "images/icons/mapPinAdd-ltr.svg",
+ "rtl": "images/icons/mapPinAdd-rtl.svg"
+ } },
+ "wikitrail": { "file": {
+ "ltr": "images/icons/wikitrail-ltr.svg",
+ "rtl": "images/icons/wikitrail-rtl.svg"
+ } }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-media.json b/resources/lib/oojs-ui/themes/mediawiki/icons-media.json
new file mode 100644
index 00000000..1c6da5a3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-media.json
@@ -0,0 +1,33 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "image": { "file": {
+ "ltr": "images/icons/image-ltr.svg",
+ "rtl": "images/icons/image-rtl.svg"
+ } },
+ "imageAdd": { "file": {
+ "ltr": "images/icons/imageAdd-ltr.svg",
+ "rtl": "images/icons/imageAdd-rtl.svg"
+ } },
+ "imageLock": { "file": {
+ "ltr": "images/icons/imageLock-ltr.svg",
+ "rtl": "images/icons/imageLock-rtl.svg"
+ } },
+ "photoGallery": { "file": {
+ "ltr": "images/icons/photoGallery-ltr.svg",
+ "rtl": "images/icons/photoGallery-rtl.svg"
+ } },
+ "play": { "file": {
+ "ltr": "images/icons/play-ltr.svg",
+ "rtl": "images/icons/play-rtl.svg"
+ } },
+ "stop": { "file": "images/icons/stop.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-moderation.json b/resources/lib/oojs-ui/themes/mediawiki/icons-moderation.json
new file mode 100644
index 00000000..fb1deb1e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-moderation.json
@@ -0,0 +1,59 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ },
+ "progressive": {
+ "color": "#347BFF"
+ },
+ "constructive": {
+ "color": "#00AF89"
+ },
+ "destructive": {
+ "color": "#D11D13"
+ },
+ "warning": {
+ "color": "#FF5D00"
+ }
+ },
+ "images": {
+ "block": { "file": "images/icons/block.svg", "variants": [ "destructive" ] },
+ "blockUndo": { "file": {
+ "ltr": "images/icons/blockUndo-ltr.svg",
+ "rtl": "images/icons/blockUndo-rtl.svg"
+ } },
+ "flag": { "file": {
+ "ltr": "images/icons/flag-ltr.svg",
+ "rtl": "images/icons/flag-rtl.svg"
+ } },
+ "flagUndo": { "file": {
+ "ltr": "images/icons/flagUndo-ltr.svg",
+ "rtl": "images/icons/flagUndo-rtl.svg"
+ } },
+ "lock": { "file": {
+ "ltr": "images/icons/lock-ltr.svg",
+ "rtl": "images/icons/lock-rtl.svg"
+ }, "variants": [ "destructive" ] },
+ "ongoingConversation": {
+ "file": {
+ "ltr": "images/icons/ongoingConversation-ltr.svg",
+ "rtl": "images/icons/ongoingConversation-rtl.svg"
+ },
+ "variants": [ "progressive" ]
+ },
+ "star": { "file": "images/icons/star.svg", "variants": [ "constructive" ] },
+ "trash": { "file": "images/icons/trash.svg" },
+ "trashUndo": { "file": {
+ "ltr": "images/icons/trashUndo-ltr.svg",
+ "rtl": "images/icons/trashUndo-rtl.svg"
+ } },
+ "unLock": { "file": {
+ "ltr": "images/icons/unLock-ltr.svg",
+ "rtl": "images/icons/unLock-rtl.svg"
+ }, "variants": [ "destructive" ] },
+ "unStar": { "file": "images/icons/unStar.svg", "variants": [ "constructive" ] }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-movement.json b/resources/lib/oojs-ui/themes/mediawiki/icons-movement.json
new file mode 100644
index 00000000..83055808
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-movement.json
@@ -0,0 +1,33 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "arrowNext": { "file": {
+ "ltr": "images/icons/arrow-ltr.svg",
+ "rtl": "images/icons/arrow-rtl.svg"
+ } },
+ "arrowLast": { "file": {
+ "ltr": "images/icons/arrow-rtl.svg",
+ "rtl": "images/icons/arrow-ltr.svg"
+ } },
+ "caretNext": { "file": {
+ "ltr": "images/icons/caret-rtl.svg",
+ "rtl": "images/icons/caret-ltr.svg"
+ } },
+ "caretLast": { "file": {
+ "ltr": "images/icons/caret-ltr.svg",
+ "rtl": "images/icons/caret-rtl.svg"
+ } },
+ "caretDown": { "file": "images/icons/caretDown.svg" },
+ "caretUp": { "file": "images/icons/caretUp.svg" },
+ "downTriangle": { "file": "images/icons/downTriangle.svg" },
+ "move": { "file": "images/icons/move.svg" },
+ "upTriangle": { "file": "images/icons/upTriangle.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-user.json b/resources/lib/oojs-ui/themes/mediawiki/icons-user.json
new file mode 100644
index 00000000..e2b2c824
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-user.json
@@ -0,0 +1,25 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "userActive": { "file": {
+ "ltr": "images/icons/userActive-ltr.svg",
+ "rtl": "images/icons/userActive-rtl.svg"
+ } },
+ "userAvatar": { "file": "images/icons/userAvatar.svg" },
+ "userInactive": { "file": {
+ "ltr": "images/icons/userInactive-ltr.svg",
+ "rtl": "images/icons/userInactive-rtl.svg"
+ } },
+ "userTalk": { "file": {
+ "ltr": "images/icons/userTalk-ltr.svg",
+ "rtl": "images/icons/userTalk-rtl.svg"
+ } }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons-wikimedia.json b/resources/lib/oojs-ui/themes/mediawiki/icons-wikimedia.json
new file mode 100644
index 00000000..911eb6f6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons-wikimedia.json
@@ -0,0 +1,15 @@
+{
+ "prefix": "oo-ui-icon",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "logoCC": { "file": "images/icons/logo-cc.svg" },
+ "logoWikimediaCommons": { "file": "images/icons/logo-wikimediaCommons.svg" },
+ "logoWikipedia": { "file": "images/icons/logo-wikipedia.svg" }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/icons.json b/resources/lib/oojs-ui/themes/mediawiki/icons.json
new file mode 100644
index 00000000..a79b3295
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/icons.json
@@ -0,0 +1,76 @@
+{
+ "selectorWithoutVariant": ".oo-ui-icon-{name}",
+ "selectorWithVariant": ".oo-ui-image-{variant}.oo-ui-icon-{name}",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ },
+ "progressive": {
+ "color": "#347BFF"
+ },
+ "constructive": {
+ "color": "#00AF89"
+ },
+ "destructive": {
+ "color": "#D11D13"
+ },
+ "warning": {
+ "color": "#FF5D00"
+ }
+ },
+ "images": {
+ "add": { "file": "images/icons/add.svg", "variants": [ "constructive" ] },
+ "advanced": { "file": "images/icons/advanced.svg" },
+ "alert": { "file": "images/icons/alert.svg", "variants": [ "warning" ] },
+ "cancel": { "file": "images/icons/cancel.svg" },
+ "check": { "file": "images/icons/check.svg", "variants": [ "constructive", "progressive", "destructive" ] },
+ "circle": { "file": "images/icons/circle.svg", "variants": [ "constructive" ] },
+ "close": { "file": {
+ "ltr": "images/icons/close-ltr.svg",
+ "rtl": "images/icons/close-rtl.svg"
+ } },
+ "code": { "file": "images/icons/code.svg" },
+ "collapse": { "file": "images/icons/collapse.svg" },
+ "comment": { "file": "images/icons/comment.svg" },
+ "ellipsis": { "file": "images/icons/ellipsis.svg" },
+ "expand": { "file": "images/icons/expand.svg" },
+ "help": { "file": {
+ "ltr": "images/icons/help-ltr.svg",
+ "rtl": "images/icons/help-rtl.svg",
+ "lang": {
+ "he,yi": "images/icons/help-ltr.svg"
+ }
+ } },
+ "history": { "file": "images/icons/history.svg" },
+ "info": { "file": "images/icons/info.svg" },
+ "menu": { "file": "images/icons/menu.svg" },
+ "next": { "file": {
+ "ltr": "images/icons/move-ltr.svg",
+ "rtl": "images/icons/move-rtl.svg"
+ } },
+ "notice": { "file": "images/icons/notice.svg" },
+ "picture": { "file": "images/icons/picture.svg" },
+ "previous": { "file": {
+ "ltr": "images/icons/move-rtl.svg",
+ "rtl": "images/icons/move-ltr.svg"
+ } },
+ "redo": { "file": {
+ "ltr": "images/icons/arched-arrow-ltr.svg",
+ "rtl": "images/icons/arched-arrow-rtl.svg"
+ } },
+ "remove": { "file": "images/icons/remove.svg", "variants": [ "destructive" ] },
+ "search": { "file": {
+ "ltr": "images/icons/search-ltr.svg",
+ "rtl": "images/icons/search-rtl.svg"
+ } },
+ "settings": { "file": "images/icons/settings.svg" },
+ "tag": { "file": "images/icons/tag.svg", "variants": [ "destructive", "warning", "constructive", "progressive" ] },
+ "undo": { "file": {
+ "ltr": "images/icons/arched-arrow-rtl.svg",
+ "rtl": "images/icons/arched-arrow-ltr.svg"
+ } },
+ "window": { "file": "images/icons/window.svg" }
+ }
+}
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
index 0d37afab..ef2ac5c0 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-constructive.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"><style>* { fill: #00AF89 }</style>
<g id="add">
- <path id="plus" d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
+ <path id="plus" d="M13 8h-2v3H8v2h3v3h2v-3h3v-2h-3z"/>
</g>
</svg>
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
index 93a1c6ef..2ad5f601 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add-invert.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"><style>* { fill: #FFFFFF }</style>
<g id="add">
- <path id="plus" d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
+ <path id="plus" d="M13 8h-2v3H8v2h3v3h2v-3h3v-2h-3z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/add.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/add.svg
index 29e5dba8..85e39feb 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/add.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">
- <path id="plus" d="M13 8h-2v3h-3v2h3v3h2v-3h3v-2h-3z"/>
+ <path id="plus" d="M13 8h-2v3H8v2h3v3h2v-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
index 733c3f97..ba0b4773 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.png
+++ 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
index fe3dc5b2..7813622f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced-invert.svg
@@ -1,4 +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"/>
+ <path d="M20 13.44v-2.88l-1.8-.3c-.1-.397-.3-.794-.6-1.39l1.1-1.49-2.1-2.088-1.5 1.093c-.5-.298-1-.497-1.4-.596L13.5 4h-2.9l-.3 1.79c-.5.098-.9.297-1.4.595L7.4 5.292 5.3 7.38l1 1.49c-.3.496-.4.894-.6 1.39l-1.7.2v2.882l1.8.298c.1.497.3.894.6 1.39l-1 1.492 2.1 2.087L9 17.61c.4.2.9.397 1.4.596l.3 1.79h3l.3-1.79c.5-.1.9-.298 1.4-.596l1.5 1.093L19 16.62l-1.1-1.49c.3-.496.5-.993.6-1.39l1.5-.3zm-8 1.492c-1.7 0-3-1.292-3-2.982 0-1.69 1.3-2.98 3-2.98s3 1.29 3 2.98-1.3 2.982-3 2.982z"/>
</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
index 7dab898d..c2a2e5e0 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.png
+++ 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
index b4629bf9..a68158d2 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/advanced.svg
@@ -1,4 +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"/>
+ <path d="M20 13.44v-2.88l-1.8-.3c-.1-.397-.3-.794-.6-1.39l1.1-1.49-2.1-2.088-1.5 1.093c-.5-.298-1-.497-1.4-.596L13.5 4h-2.9l-.3 1.79c-.5.098-.9.297-1.4.595L7.4 5.292 5.3 7.38l1 1.49c-.3.496-.4.894-.6 1.39l-1.7.2v2.882l1.8.298c.1.497.3.894.6 1.39l-1 1.492 2.1 2.087L9 17.61c.4.2.9.397 1.4.596l.3 1.79h3l.3-1.79c.5-.1.9-.298 1.4-.596l1.5 1.093L19 16.62l-1.1-1.49c.3-.496.5-.993.6-1.39l1.5-.3zm-8 1.492c-1.7 0-3-1.292-3-2.982 0-1.69 1.3-2.98 3-2.98s3 1.29 3 2.98-1.3 2.982-3 2.982z"/>
</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
index 5440113f..6071d882 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.png
+++ 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
index 715a3f55..55621b9d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-invert.svg
@@ -2,7 +2,7 @@
<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"/>
+ <path id="stroke" d="M13.516 10h-3L11 15h2z"/>
+ <path id="triangle" d="M12.017 5.974L19.537 19H4.497l7.52-13.026m0-2.474c-.545 0-1.09.357-1.5 1.07L2.53 18.403C1.705 19.833 2.38 21 4.03 21H20c1.65 0 2.325-1.17 1.5-2.6L13.517 4.575c-.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
index fcf98c5d..82bcd068 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.png
+++ 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
index 6928cab4..bdf0ac23 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert-warning.svg
@@ -2,7 +2,7 @@
<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"/>
+ <path id="stroke" d="M13.516 10h-3L11 15h2z"/>
+ <path id="triangle" d="M12.017 5.974L19.537 19H4.497l7.52-13.026m0-2.474c-.545 0-1.09.357-1.5 1.07L2.53 18.403C1.705 19.833 2.38 21 4.03 21H20c1.65 0 2.325-1.17 1.5-2.6L13.517 4.575c-.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
index e98a14a9..98e94fbe 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.svg
index f0c65224..8b601d5b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/alert.svg
@@ -2,7 +2,7 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<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"/>
+ <path id="stroke" d="M13.516 10h-3L11 15h2z"/>
+ <path id="triangle" d="M12.017 5.974L19.537 19H4.497l7.52-13.026m0-2.474c-.545 0-1.09.357-1.5 1.07L2.53 18.403C1.705 19.833 2.38 21 4.03 21H20c1.65 0 2.325-1.17 1.5-2.6L13.517 4.575c-.413-.715-.956-1.072-1.5-1.072z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center-invert.png
new file mode 100644
index 00000000..0cdfef90
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center-invert.svg
new file mode 100644
index 00000000..939962cf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center-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="align-center">
+ <path d="M9 9h6c.554 0 1 .446 1 1v5c0 .554-.446 1-1 1H9c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zm-5.5 9h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0-12h17c.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-center.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.svg
index 887c2f66..4697eb9f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-center.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="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"/>
+ <path d="M9 9h6c.554 0 1 .446 1 1v5c0 .554-.446 1-1 1H9c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zm-5.5 9h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0-12h17c.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left-invert.png
new file mode 100644
index 00000000..a2338b9c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left-invert.svg
new file mode 100644
index 00000000..aba4fbfc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left-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="align-float-left">
+ <path d="M4 9h6c.554 0 1 .446 1 1v5c0 .554-.446 1-1 1H4c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zm9.5 0h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0 3h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0 3h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm-10-9h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0 12h17c.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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-left.svg
index ce9761e2..1c95377b 100644
--- 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
@@ -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="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"/>
+ <path d="M4 9h6c.554 0 1 .446 1 1v5c0 .554-.446 1-1 1H4c-.554 0-1-.446-1-1v-5c0-.554.446-1 1-1zm9.5 0h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0 3h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0 3h7c.277 0 .5.223.5.5s-.223.5-.5.5h-7c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm-10-9h17c.277 0 .5.223.5.5s-.223.5-.5.5h-17c-.277 0-.5-.223-.5-.5s.223-.5.5-.5zm0 12h17c.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right-invert.png
new file mode 100644
index 00000000..80d5f6be
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right-invert.svg
new file mode 100644
index 00000000..9f6eca8e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right-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="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-1zm-9.5 0h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm0 3h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm0 3h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm10-9h-17c-.277 0-.5.223-.5.5s.223.5.5.5h17c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm0 12h-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/align-float-right.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/align-float-right.svg
index 557692ae..2467f7f8 100644
--- 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
@@ -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="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"/>
+ <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-1zm-9.5 0h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm0 3h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm0 3h-7c-.277 0-.5.223-.5.5s.223.5.5.5h7c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm10-9h-17c-.277 0-.5.223-.5.5s.223.5.5.5h17c.277 0 .5-.223.5-.5s-.223-.5-.5-.5zm0 12h-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
index 37b57fe5..327e1dd6 100644
--- 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
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
index 9aca4158..df95976f 100644
--- 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
@@ -1,6 +1,4 @@
-<?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>
+<?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="M13.3 6.3l6.3 5.7-6.3 5.7v-3.8H12c-3.2 0-6.3 1.3-7.6 3.8 0-4.7 2.8-7.6 7.9-7.6h.9V6.3z" id="path3034"/>
+</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
index 7d2113f2..649cd143 100644
--- 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
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
index 049f21e2..9abef4fc 100644
--- 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
@@ -1,6 +1,4 @@
-<?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>
+<?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="M13.3 6.3l6.3 5.7-6.3 5.7v-3.8H12c-3.2 0-6.3 1.3-7.6 3.8 0-4.7 2.8-7.6 7.9-7.6h.9V6.3z" id="path3034"/>
+</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
index a50b3066..f04017c1 100644
--- 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
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
index 11fffcb2..d957f708 100644
--- 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
@@ -1,6 +1,4 @@
-<?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>
+<?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="M10.7 6.3L4.4 12l6.3 5.7v-3.8H12c3.2 0 6.3 1.3 7.6 3.8 0-4.7-2.8-7.6-7.9-7.6h-.9V6.3z" id="path3034"/>
+</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
index ed69a011..d5917686 100644
--- 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
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
index 20875f34..6ec2fcc8 100644
--- 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
@@ -1,6 +1,4 @@
-<?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>
+<?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="M10.7 6.3L4.4 12l6.3 5.7v-3.8H12c3.2 0 6.3 1.3 7.6 3.8 0-4.7-2.8-7.6-7.9-7.6h-.9V6.3z" id="path3034"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr-invert.png
new file mode 100644
index 00000000..15b0e445
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr-invert.svg
new file mode 100644
index 00000000..e3e4b98d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-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="g4">
+ <path d="M16 12H6c-1.7 0-3 1.3-3 3h13v3l5-4.5L16 9v3z" id="path6"/>
+ </g>
+</svg>
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
index b07621e8..a0097cb4 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-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="g4">
- <path d="M16 12h-10c-1.7 0-3 1.3-3 3h13v3l5-4.5-5-4.5v3z" id="path6"/>
+ <path d="M16 12H6c-1.7 0-3 1.3-3 3h13v3l5-4.5L16 9v3z" id="path6"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl-invert.png
new file mode 100644
index 00000000..bef0ab41
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl-invert.svg
new file mode 100644
index 00000000..1e9cdab7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-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>
+ <path d="M8 12h10c1.7 0 3 1.3 3 3H8v3l-5-4.5L8 9v3z"/>
+ </g>
+</svg>
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
index a0189283..54d6d259 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/arrow-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>
- <path d="M8 12h10c1.7 0 3 1.3 3 3h-13v3l-5-4.5 5-4.5v3z"/>
+ <path d="M8 12h10c1.7 0 3 1.3 3 3H8v3l-5-4.5L8 9v3z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr-invert.png
new file mode 100644
index 00000000..764b7c08
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr-invert.svg
new file mode 100644
index 00000000..aec5f507
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-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="M12 10h4V5h-4v5zm-5 2h9v-1H7v1zm0 2h9v-1H7v1zm0 2h9v-1H7v1zm4-9H7v1h4V7zm0 2H7v1h4V9zm0-4H7v1h4V5zM5 3h13v16H8c-1.7 0-3-1.3-3-3V3z"/>
+ </g>
+</svg>
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
index b719946d..e8a1ad39 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-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>
- <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"/>
+ <path d="M12 10h4V5h-4v5zm-5 2h9v-1H7v1zm0 2h9v-1H7v1zm0 2h9v-1H7v1zm4-9H7v1h4V7zm0 2H7v1h4V9zm0-4H7v1h4V5zM5 3h13v16H8c-1.7 0-3-1.3-3-3V3z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl-invert.png
new file mode 100644
index 00000000..b7013394
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl-invert.svg
new file mode 100644
index 00000000..87cb725f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-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="g16">
+ <path d="M11 10H7V5h4v5zm5 2H7v-1h9v1zm0 2H7v-1h9v1zm0 2H7v-1h9v1zm-4-9h4v1h-4V7zm0 2h4v1h-4V9zm0-4h4v1h-4V5zm6-2H5v16h10c1.7 0 3-1.3 3-3V3z" id="path18"/>
+ </g>
+</svg>
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
index f14dfbda..ab4398ee 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/article-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="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"/>
+ <path d="M11 10H7V5h4v5zm5 2H7v-1h9v1zm0 2H7v-1h9v1zm0 2H7v-1h9v1zm-4-9h4v1h-4V7zm0 2h4v1h-4V9zm0-4h4v1h-4V5zm6-2H5v16h10c1.7 0 3-1.3 3-3V3z" id="path18"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr-invert.png
new file mode 100644
index 00000000..f67ac4ac
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr-invert.svg
new file mode 100644
index 00000000..81e2adda
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-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>
+ <g>
+ <path d="M21 11l-6 7-4-4-1 1 5 5 7-8z"/>
+ </g>
+ <path d="M17 14V3H4v13c0 1.7 1.3 3 3 3h5l-3-3H6v-1h2.6l1-1H6v-1h9v1h-2l1 1h2l1-1zM6 5h4v1H6V5zm0 2h4v1H6V7zm0 2h4v1H6V9zm9 3H6v-1h9v1zm-4-2V5h4v5h-4z"/>
+ </g>
+</svg>
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
index 77119710..08afca27 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-ltr.svg
@@ -4,6 +4,6 @@
<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"/>
+ <path d="M17 14V3H4v13c0 1.7 1.3 3 3 3h5l-3-3H6v-1h2.6l1-1H6v-1h9v1h-2l1 1h2l1-1zM6 5h4v1H6V5zm0 2h4v1H6V7zm0 2h4v1H6V9zm9 3H6v-1h9v1zm-4-2V5h4v5h-4z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl-invert.png
new file mode 100644
index 00000000..1db4c2e5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl-invert.svg
new file mode 100644
index 00000000..f9ec5b6a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-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="g28">
+ <g id="g30">
+ <path d="M5 11l6 7 4-4 1 1-5 5-7-8z" id="path32"/>
+ </g>
+ <path d="M9 14V3h13v13c0 1.7-1.3 3-3 3h-5l3-3h3v-1h-2.6l-1-1H20v-1h-9v1h2l-1 1h-2l-1-1zm11-9h-4v1h4V5zm0 2h-4v1h4V7zm0 2h-4v1h4V9zm-9 3h9v-1h-9v1zm4-2V5h-4v5h4z" id="path34"/>
+ </g>
+</svg>
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
index 771b3ffb..e405ff58 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleCheck-rtl.svg
@@ -4,6 +4,6 @@
<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"/>
+ <path d="M9 14V3h13v13c0 1.7-1.3 3-3 3h-5l3-3h3v-1h-2.6l-1-1H20v-1h-9v1h2l-1 1h-2l-1-1zm11-9h-4v1h4V5zm0 2h-4v1h4V7zm0 2h-4v1h4V9zm-9 3h9v-1h-9v1zm4-2V5h-4v5h4z" id="path34"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr-invert.png
new file mode 100644
index 00000000..7f7b0a34
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr-invert.svg
new file mode 100644
index 00000000..5398dc8f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-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="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.3zM11.8 13c.3-.4.6-.7 1-1H7v-1h9s1.2 0 2 .6V3H5v13c0 1.7 1.3 3 3 3h3.8c-.6-.8-1-1.9-1-3H7v-1h3.9l.3-1H7v-1h4.8zm.2-8h4v5h-4V5zM7 5h4v1H7V5zm0 2h4v1H7V7zm0 2h4v1H7V9z"/>
+ </g>
+</svg>
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
index e54c0c4a..fcbe4ee6 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-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>
- <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"/>
+ <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.3zM11.8 13c.3-.4.6-.7 1-1H7v-1h9s1.2 0 2 .6V3H5v13c0 1.7 1.3 3 3 3h3.8c-.6-.8-1-1.9-1-3H7v-1h3.9l.3-1H7v-1h4.8zm.2-8h4v5h-4V5zM7 5h4v1H7V5zm0 2h4v1H7V7zm0 2h4v1H7V9z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl-invert.png
new file mode 100644
index 00000000..dafab9ba
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl-invert.svg
new file mode 100644
index 00000000..33bcf2ad
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-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="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.7L5 21.2l2.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 .6V3h13v13c0 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-4v5h4V5zm5 0h-4v1h4V5zm0 2h-4v1h4V7zm0 2h-4v1h4V9z" id="path46"/>
+ </g>
+</svg>
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
index 31134f1c..7ded2320 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/articleSearch-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="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"/>
+ <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.7L5 21.2l2.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 .6V3h13v13c0 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-4v5h4V5zm5 0h-4v1h4V5zm0 2h-4v1h4V7zm0 2h-4v1h4V9z" id="path46"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.png
new file mode 100644
index 00000000..16d67efd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-invert.svg
new file mode 100644
index 00000000..13f6edef
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell-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="M17.5 14V9c0-3-2.3-5-5.5-5S6.5 6 6.5 9v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 20H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.svg
index df08800f..787ed141 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bell.svg
@@ -1,4 +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"/>
+ <path d="M17.5 14V9c0-3-2.3-5-5.5-5S6.5 6 6.5 9v5c0 2 0 3-2 3v1h15v-1c-2 0-2-1-2-3zM12 20H9c0 1 1.6 2 3 2s3-1 3-2h-3z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.png
new file mode 100644
index 00000000..e59b49de
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr-invert.svg
new file mode 100644
index 00000000..7dfcb1ca
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-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="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.5zM12 19.8l-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-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.png
index 4450e690..9572f433 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.png
+++ 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
index f419e79f..f68a8e0e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-ltr.svg
@@ -1,4 +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"/>
+ <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.5zM12 19.8l-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl-invert.png
new file mode 100644
index 00000000..114d2155
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl-invert.svg
new file mode 100644
index 00000000..03874c80
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-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="M6.21 14.7L4.51 10c-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/bellOn-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.png
index b236b999..6e71a864 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.png
+++ 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
index e4c3a3fa..ae035290 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bellOn-rtl.svg
@@ -1,4 +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"/>
+ <path d="M6.21 14.7L4.51 10c-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta-invert.png
new file mode 100644
index 00000000..7d23df24
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta-invert.svg
new file mode 100644
index 00000000..4d8c6732
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/beta-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-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch-invert.png
new file mode 100644
index 00000000..d620367f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch-invert.svg
new file mode 100644
index 00000000..5058629b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch-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="M15.3 14.7C16.1 10.9 14.7 4 12 4c-2.7 0-4.2 6.7-3.4 10.5L7 18h2.7l.3 1h4c.2-.3.1-.5.3-1H17l-1.7-3.3zM12 10c-.8 0-1.5-.7-1.5-1.5S11.2 7 12 7s1.5.7 1.5 1.5S12.8 10 12 10zm2 10c0 1.1-2 2-2 2s-2-.9-2-2"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.svg
index a693b59b..c3f99d6a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/betaLaunch.svg
@@ -1,4 +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"/>
+ <path d="M15.3 14.7C16.1 10.9 14.7 4 12 4c-2.7 0-4.2 6.7-3.4 10.5L7 18h2.7l.3 1h4c.2-.3.1-.5.3-1H17l-1.7-3.3zM12 10c-.8 0-1.5-.7-1.5-1.5S11.2 7 12 7s1.5.7 1.5 1.5S12.8 10 12 10zm2 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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr-invert.png
new file mode 100644
index 00000000..867a1d8b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr-invert.svg
new file mode 100644
index 00000000..9b3cdeba
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr-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>
+ <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="M15.5 9h7L19 3z"/>
+ </g>
+</svg>
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
index 94ec6704..6d95fc66 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-ltr.svg
@@ -1,7 +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>
+ <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="M15.5 9h7L19 3z"/>
+ </g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl-invert.png
new file mode 100644
index 00000000..25751080
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl-invert.svg
new file mode 100644
index 00000000..3d00d673
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl-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>
+ <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/bigger-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.svg
index b2a6c139..807cdd91 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bigger-rtl.svg
@@ -1,7 +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>
+ <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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.svg
index c850e65b..1447b77e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-destructive.svg
@@ -1,4 +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"/>
+ <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 9H7v-2h10v2z" id="path4"/>
</svg>
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
index 289ef4fd..db7d0f78 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block-invert.svg
@@ -1,4 +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"/>
+ <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 9H7v-2h10v2z" id="path4"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/block.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block.svg
index 0ddd1d47..6299c30e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/block.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/block.svg
@@ -1,4 +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"/>
+ <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 9H7v-2h10v2z" id="path4"/>
</svg>
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
index 94089371..6a542dcd 100644
--- 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
@@ -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"><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"/>
+ <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.4L13 11h4zM4 4L3 5l2.4 2.4C4.5 8.7 4 10.3 4 12c0 4.4 3.6 8 8 8 1.7 0 3.3-.5 4.6-1.4L19 21l1-1L4 4zm3 9v-2h2l2 2H7z" id="path68"/>
</g>
</svg>
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
index 3d9cfd7d..f6d5486d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-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="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"/>
+ <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.4L13 11h4zM4 4L3 5l2.4 2.4C4.5 8.7 4 10.3 4 12c0 4.4 3.6 8 8 8 1.7 0 3.3-.5 4.6-1.4L19 21l1-1L4 4zm3 9v-2h2l2 2H7z" id="path68"/>
</g>
</svg>
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
index ba48235d..4080e8d1 100644
--- 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
@@ -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"><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"/>
+ <path d="M7 11v2h2l-3.6 3.6C4.5 15.3 4 13.7 4 12c0-4.4 3.6-8 8-8 1.7 0 3.3.5 4.6 1.4L11 11H7zm13-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.4L5 21l-1-1L20 4zm-3 9v-2h-2l-2 2h4z" id="path68"/>
</g>
</svg>
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
index 8f807596..d0ddde0e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/blockUndo-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="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"/>
+ <path d="M7 11v2h2l-3.6 3.6C4.5 15.3 4 13.7 4 12c0-4.4 3.6-8 8-8 1.7 0 3.3.5 4.6 1.4L11 11H7zm13-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.4L5 21l-1-1L20 4zm-3 9v-2h-2l-2 2h4z" id="path68"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a-invert.png
new file mode 100644
index 00000000..7d531fe9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a-invert.svg
new file mode 100644
index 00000000..77d0c23a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a-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="bold-a">
+ <path d="M16 18h3L14 6h-3L6 18h3l1.25-3h4.5L16 18zm-4.917-5L12.5 9.6l1.417 3.4h-2.834z"/>
+ </g>
+</svg>
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
index 4b828779..d5cee050 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-a.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="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"/>
+ <path d="M16 18h3L14 6h-3L6 18h3l1.25-3h4.5L16 18zm-4.917-5L12.5 9.6l1.417 3.4h-2.834z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain-invert.png
new file mode 100644
index 00000000..30d7d205
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain-invert.svg
new file mode 100644
index 00000000..e1a7c677
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-ain-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="bold-arab-ain">
+ <path id="arab-ain" d="M9.337 13.616c0 1.35 1.386 2.1 4.16 2.258l2.186-.03.318.045c-.03.123-.25.34-.66.65l-.09.064c-1.236.93-2.423 1.393-3.56 1.393-1.143 0-2.046-.33-2.71-.99-.65-.66-.976-1.56-.976-2.7.006-1.353.567-2.572 1.685-3.657v-.043l-.607-.55c-.15-.18-.222-.39-.222-.63 0-.49.24-1.11.718-1.863.65-1.046 1.303-1.566 1.958-1.56.886.004 1.618.42 2.194 1.245.324.48-.03.55-1.065.22-.842-.33-1.527-.05-2.054.826l.016.074 1.123.866.05.005c1.404-.496 2.418-.74 3.043-.724-.058.116-.14.36-.243.732-.105.357-.206.684-.305.982l-.126.373-.386.05c-1.743.24-2.992.716-3.745 1.43-.464.463-.698.972-.703 1.524"/>
+ </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
index 871da471..e9dce687 100644
--- 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
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
index f96cebce..23ed091a 100644
--- 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
@@ -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="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"/>
+ <path id="arab-ain" d="M9.337 13.616c0 1.35 1.386 2.1 4.16 2.258l2.186-.03.318.045c-.03.123-.25.34-.66.65l-.09.064c-1.236.93-2.423 1.393-3.56 1.393-1.143 0-2.046-.33-2.71-.99-.65-.66-.976-1.56-.976-2.7.006-1.353.567-2.572 1.685-3.657v-.043l-.607-.55c-.15-.18-.222-.39-.222-.63 0-.49.24-1.11.718-1.863.65-1.046 1.303-1.566 1.958-1.56.886.004 1.618.42 2.194 1.245.324.48-.03.55-1.065.22-.842-.33-1.527-.05-2.054.826l.016.074 1.123.866.05.005c1.404-.496 2.418-.74 3.043-.724-.058.116-.14.36-.243.732-.105.357-.206.684-.305.982l-.126.373-.386.05c-1.743.24-2.992.716-3.745 1.43-.464.463-.698.972-.703 1.524"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad-invert.png
new file mode 100644
index 00000000..9eb593bd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad-invert.svg
new file mode 100644
index 00000000..8b75d71c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad-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="bold-arab-dad">
+ <path id="arab-dad" d="M16.41 8.232l-1.675-.665L15.43 6l1.687.64-.707 1.592m.775 3.078c-.51-.286-1-.427-1.476-.423-.475 0-.986.205-1.536.616l-.506.38.006.024c1.084.066 1.934.1 2.55.1h.314c.57-.022.994-.065 1.278-.132-.067-.17-.275-.36-.625-.566h-.005M10.382 14.6c-.017-.904-.33-1.87-.938-2.898l1.294-1.73.118.15c.267.336.504.924.713 1.766l.065.05c.496-.007.942-.17 1.338-.484v-.006l1.732-1.53c.68-.6 1.282-.9 1.807-.9.384.003.85.194 1.395.57.55.378.884.697 1 .96.063.15.094.385.094.71 0 .694-.11 1.227-.33 1.596-.192.31-.473.555-.844.734-.438.208-1.55.312-3.333.312-.8 0-1.794-.02-2.982-.062l-.143.43c-.254.67-.463 1.112-.625 1.323-.725.937-1.786 1.405-3.183 1.405C5.85 16.99 5 16.076 5 14.256c.003-.94.278-1.814.824-2.618.15-.216.298-.367.444-.454.225-.133.288-.09.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-arab-dad.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-arab-dad.png
index ad6f342f..46d579b8 100644
--- 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
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
index f04c6aad..7e6769d9 100644
--- 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
@@ -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="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"/>
+ <path id="arab-dad" d="M16.41 8.232l-1.675-.665L15.43 6l1.687.64-.707 1.592m.775 3.078c-.51-.286-1-.427-1.476-.423-.475 0-.986.205-1.536.616l-.506.38.006.024c1.084.066 1.934.1 2.55.1h.314c.57-.022.994-.065 1.278-.132-.067-.17-.275-.36-.625-.566h-.005M10.382 14.6c-.017-.904-.33-1.87-.938-2.898l1.294-1.73.118.15c.267.336.504.924.713 1.766l.065.05c.496-.007.942-.17 1.338-.484v-.006l1.732-1.53c.68-.6 1.282-.9 1.807-.9.384.003.85.194 1.395.57.55.378.884.697 1 .96.063.15.094.385.094.71 0 .694-.11 1.227-.33 1.596-.192.31-.473.555-.844.734-.438.208-1.55.312-3.333.312-.8 0-1.794-.02-2.982-.062l-.143.43c-.254.67-.463 1.112-.625 1.323-.725.937-1.786 1.405-3.183 1.405C5.85 16.99 5 16.076 5 14.256c.003-.94.278-1.814.824-2.618.15-.216.298-.367.444-.454.225-.133.288-.09.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to-invert.png
new file mode 100644
index 00000000..03a79311
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to-invert.svg
new file mode 100644
index 00000000..0176bb22
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-armn-to-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="bold-armn-to">
+ <path id="armn-to" d="M13.86 16.257c.124 0 .254-.026.39-.078.135-.06.257-.15.367-.278.114-.13.205-.302.273-.516.073-.214.11-.48.11-.798V13h-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.214.18.39.29.53.12.132.25.23.387.29.14.05.276.073.406.073m-2.97-7.84c-.37.082-.694.247-.975.45-.28.198-.505.47-.672.813-.16.342-.242.78-.242 1.31V18H6v-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.344.49.734.64 1.17.15.43.226 1.09.226 1.61h1.357v2.04H17.78v1.6c0 .58-.103 1.09-.31 1.54-.21.44-.49.81-.845 1.113-.35.302-.834.53-1.297.687-.464.15-.953.227-1.47.227-.51 0-.996-.08-1.46-.235-.464-.156-.87-.39-1.22-.703-.348-.315-.626-.705-.835-1.174-.203-.473-.304-1.028-.304-1.663s.1-1.182.32-1.64c.21-.46.493-.685.85-.977.35-.297.76-.513 1.22-.648.454-.14.93-.21 1.43-.21h1.13c-.01-.49-.04-1.044-.24-1.36-.2-.324-.457-.58-.77-.767-.31-.192-.598-.33-.984-.425-.375-.09-.578-.094-1.1-.094-.52 0-.64.02-1.01.103z"/>
+ </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
index c4af66e7..5e16e38f 100644
--- 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
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
index 4dbec6d9..7471d1a3 100644
--- 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
@@ -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="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"/>
+ <path id="armn-to" d="M13.86 16.257c.124 0 .254-.026.39-.078.135-.06.257-.15.367-.278.114-.13.205-.302.273-.516.073-.214.11-.48.11-.798V13h-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.214.18.39.29.53.12.132.25.23.387.29.14.05.276.073.406.073m-2.97-7.84c-.37.082-.694.247-.975.45-.28.198-.505.47-.672.813-.16.342-.242.78-.242 1.31V18H6v-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.344.49.734.64 1.17.15.43.226 1.09.226 1.61h1.357v2.04H17.78v1.6c0 .58-.103 1.09-.31 1.54-.21.44-.49.81-.845 1.113-.35.302-.834.53-1.297.687-.464.15-.953.227-1.47.227-.51 0-.996-.08-1.46-.235-.464-.156-.87-.39-1.22-.703-.348-.315-.626-.705-.835-1.174-.203-.473-.304-1.028-.304-1.663s.1-1.182.32-1.64c.21-.46.493-.685.85-.977.35-.297.76-.513 1.22-.648.454-.14.93-.21 1.43-.21h1.13c-.01-.49-.04-1.044-.24-1.36-.2-.324-.457-.58-.77-.767-.31-.192-.598-.33-.984-.425-.375-.09-.578-.094-1.1-.094-.52 0-.64.02-1.01.103z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b-invert.png
new file mode 100644
index 00000000..1f96ddfa
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b-invert.svg
new file mode 100644
index 00000000..78ab202d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b-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="bold-b">
+ <path id="b" d="M7 18h6c2 0 4-1 4-3 0-1.064.01-1.975-1.99-3 2-.975 1.99-1.935 1.99-3 0-2-2-3-4-3H7v12zm7-8c0 1 0 1-2 1h-2V8h2c2 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-b.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.svg
index 4f648203..1806709a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-b.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="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"/>
+ <path id="b" d="M7 18h6c2 0 4-1 4-3 0-1.064.01-1.975-1.99-3 2-.975 1.99-1.935 1.99-3 0-2-2-3-4-3H7v12zm7-8c0 1 0 1-2 1h-2V8h2c2 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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be-invert.png
new file mode 100644
index 00000000..7ea90928
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be-invert.svg
new file mode 100644
index 00000000..396215dc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-be-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="bold-cyrl-be">
+ <path id="cyrl-be" d="M7 6h9v2h-6v3h2.65c.892 0 1.632.11 2.22.327.587.218 1.087.622 1.5 1.21.42.59.63 1.188.63 1.98 0 .812-.21 1.397-.63 1.976-.418.578-.897.974-1.436 1.187-.533.213-1.295.32-2.286.32h-5.65m4.768-2c.75 0 1.28-.05 1.584-.12.305-.077.57-.247.792-.51.23-.26.343-.472.343-.854 0-.557-.2-.868-.596-1.12-.396-.255-1.068-.397-2.02-.397H10v3"/>
+ </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
index dc310511..07a721b5 100644
--- 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
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
index 279466d4..383ef323 100644
--- 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
@@ -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="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"/>
+ <path id="cyrl-be" d="M7 6h9v2h-6v3h2.65c.892 0 1.632.11 2.22.327.587.218 1.087.622 1.5 1.21.42.59.63 1.188.63 1.98 0 .812-.21 1.397-.63 1.976-.418.578-.897.974-1.436 1.187-.533.213-1.295.32-2.286.32h-5.65m4.768-2c.75 0 1.28-.05 1.584-.12.305-.077.57-.247.792-.51.23-.26.343-.472.343-.854 0-.557-.2-.868-.596-1.12-.396-.255-1.068-.397-2.02-.397H10v3"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te-invert.png
new file mode 100644
index 00000000..82835f68
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te-invert.svg
new file mode 100644
index 00000000..740dceee
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-te-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="bold-cyrl-te">
+ <path id="te" d="M11 18V8H7V6h11v2h-4v10"/>
+ </g>
+</svg>
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
index fdeeb6c5..63aee3ea 100644
--- 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
@@ -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="bold-cyrl-te">
- <path id="te" d="M11 18v-10h-4v-2h11v2h-4v10"/>
+ <path id="te" d="M11 18V8H7V6h11v2h-4v10"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe-invert.png
new file mode 100644
index 00000000..e9cc60f9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe-invert.svg
new file mode 100644
index 00000000..3d7523a0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-cyrl-zhe-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="bold-cyrl-zhe">
+ <path id="cyrl-zhe" d="M13 6v5.154c.328-.033.537-.18.705-.447.168-.266.4-.873.698-1.82.39-1.242.79-2.034 1.197-2.375.403-.336 1.075-.504 2.014-.504L18 6v1.78l-.386-.008c-.4 0-.69.062-.878.187-.186.115-.337.3-.452.55-.115.25-.286.76-.512 1.536-.12.41-.25.755-.392 1.032-.137.275-.383.536-.738.78.44.156.8.465 1.084.926.288.454.603 1.102.944 1.942L18 18h-2.314l-1.17-3.08-.113-.253-.24-.56c-.247-.57-.45-.933-.61-1.09-.16-.157-.318-.236-.553-.236V18h-2v-5.22c-.226 0-.382.077-.546.23-.164.15-.368.517-.612 1.097l-.246.56-.113.253L8.313 18H6l1.33-3.267c.327-.808.635-1.447.923-1.92.293-.476.663-.793 1.11-.95-.355-.244-.603-.5-.745-.772-.137-.272-.268-.62-.392-1.04-.222-.76-.39-1.263-.505-1.52-.11-.252-.26-.44-.45-.57-.184-.12-.49-.183-.915-.183L6 7.782v-1.78l.386.008c.953 0 1.63.17 2.034.512.4.347.79 1.136 1.177 2.366.3.954.534 1.564.698 1.83.168.26.377.405.705.438V6.002"/>
+ </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
index 3084fef2..41e562bc 100644
--- 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
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
index 5996c813..e3499050 100644
--- 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
@@ -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="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"/>
+ <path id="cyrl-zhe" d="M13 6v5.154c.328-.033.537-.18.705-.447.168-.266.4-.873.698-1.82.39-1.242.79-2.034 1.197-2.375.403-.336 1.075-.504 2.014-.504L18 6v1.78l-.386-.008c-.4 0-.69.062-.878.187-.186.115-.337.3-.452.55-.115.25-.286.76-.512 1.536-.12.41-.25.755-.392 1.032-.137.275-.383.536-.738.78.44.156.8.465 1.084.926.288.454.603 1.102.944 1.942L18 18h-2.314l-1.17-3.08-.113-.253-.24-.56c-.247-.57-.45-.933-.61-1.09-.16-.157-.318-.236-.553-.236V18h-2v-5.22c-.226 0-.382.077-.546.23-.164.15-.368.517-.612 1.097l-.246.56-.113.253L8.313 18H6l1.33-3.267c.327-.808.635-1.447.923-1.92.293-.476.663-.793 1.11-.95-.355-.244-.603-.5-.745-.772-.137-.272-.268-.62-.392-1.04-.222-.76-.39-1.263-.505-1.52-.11-.252-.26-.44-.45-.57-.184-.12-.49-.183-.915-.183L6 7.782v-1.78l.386.008c.953 0 1.63.17 2.034.512.4.347.79 1.136 1.177 2.366.3.954.534 1.564.698 1.83.168.26.377.405.705.438V6.002"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f-invert.png
new file mode 100644
index 00000000..e695e7e0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f-invert.svg
new file mode 100644
index 00000000..14884f79
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f-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="bold-f">
+ <path id="f" d="M16 8V6H8v12h3v-5h4v-2h-4V8z"/>
+ </g>
+</svg>
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
index 357d2e5d..89061f10 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-f.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="bold-f">
- <path id="f" d="M16 8v-2h-8v12h3v-5h4v-2h-4v-3z"/>
+ <path id="f" d="M16 8V6H8v12h3v-5h4v-2h-4V8z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g-invert.png
new file mode 100644
index 00000000..5dc39ee4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g-invert.svg
new file mode 100644
index 00000000..88733e0c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g-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="bold-g">
+ <path id="g" d="M12 14v-2h5v4.203c-.497.475-1.22.894-2.166 1.26-.94.358-1.896.537-2.864.537-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.26-2.282.77-3.222.517-.94 1.27-1.66 2.26-2.16.753-.386 1.692-.58 2.815-.58 1.46 0 2.6.304 3.418.91.825.603 1.354 1.436 1.59 2.502l-2.36.435c-.165-.57-.48-1.018-.94-1.346-.453-.336-1.022-.5-1.707-.5-1.038 0-1.864.322-2.48.97-.61.65-.914 1.613-.914 2.89 0 1.377.31 2.41.93 3.103.62.686 1.434 1.03 2.44 1.03.497 0 .995-.096 1.49-.286.505-.196 1.334-.57 1.69-.846v-.866"/>
+ </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
index e30e1fea..cc4be630 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.png
+++ 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
index e032542e..05b46e2d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-g.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="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"/>
+ <path id="g" d="M12 14v-2h5v4.203c-.497.475-1.22.894-2.166 1.26-.94.358-1.896.537-2.864.537-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.26-2.282.77-3.222.517-.94 1.27-1.66 2.26-2.16.753-.386 1.692-.58 2.815-.58 1.46 0 2.6.304 3.418.91.825.603 1.354 1.436 1.59 2.502l-2.36.435c-.165-.57-.48-1.018-.94-1.346-.453-.336-1.022-.5-1.707-.5-1.038 0-1.864.322-2.48.97-.61.65-.914 1.613-.914 2.89 0 1.377.31 2.41.93 3.103.62.686 1.434 1.03 2.44 1.03.497 0 .995-.096 1.49-.286.505-.196 1.334-.57 1.69-.846v-.866"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man-invert.png
new file mode 100644
index 00000000..e699abb6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man-invert.svg
new file mode 100644
index 00000000..391127f7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-geor-man-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="bold-geor-man">
+ <path id="geor-man" d="M13.832 14.06c0-1.714-.394-2.572-1.182-2.572-.868 0-1.302.78-1.302 2.338-.01 1.624.42 2.436 1.295 2.436.793 0 1.19-.734 1.19-2.2m2.167 0C16 16.686 14.884 18 12.65 18 10.218 18 9 16.614 9 13.84c0-2.737 1.217-4.105 3.65-4.105.842 0 1.183.63 1.183.63v-1.58c0-.788-.45-1.183-1.347-1.183-.572 0-.858.374-.858 1.123h-2.34C9.29 6.908 10.35 6 12.462 6 14.83 6 16.01 6.946 16 8.84"/>
+ </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
index 814eff89..d6dcb5db 100644
--- 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
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
index b211bf7a..deb95b70 100644
--- 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
@@ -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="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"/>
+ <path id="geor-man" d="M13.832 14.06c0-1.714-.394-2.572-1.182-2.572-.868 0-1.302.78-1.302 2.338-.01 1.624.42 2.436 1.295 2.436.793 0 1.19-.734 1.19-2.2m2.167 0C16 16.686 14.884 18 12.65 18 10.218 18 9 16.614 9 13.84c0-2.737 1.217-4.105 3.65-4.105.842 0 1.183.63 1.183.63v-1.58c0-.788-.45-1.183-1.347-1.183-.572 0-.858.374-.858 1.123h-2.34C9.29 6.908 10.35 6 12.462 6 14.83 6 16.01 6.946 16 8.84"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l-invert.png
new file mode 100644
index 00000000..45a84abe
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l-invert.svg
new file mode 100644
index 00000000..20414451
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l-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="bold-l">
+ <path id="l" d="M8 18V6h3v10h5v2"/>
+ </g>
+</svg>
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
index 16797938..76956234 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-l.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="bold-l">
- <path id="l" d="M8 18v-12h3v10h5v2"/>
+ <path id="l" d="M8 18V6h3v10h5v2"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n-invert.png
new file mode 100644
index 00000000..13b5b72d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n-invert.svg
new file mode 100644
index 00000000..667bec4d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n-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="bold-n">
+ <path id="n" d="M7 18V6h3l4 8V6h3v12h-3l-4-8v8H7"/>
+ </g>
+</svg>
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
index 73ad019a..62f66a2f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-n.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="bold-n">
- <path id="n" d="M7 18v-12h3l4 8v-8h3v12h-3l-4-8v8h-3"/>
+ <path id="n" d="M7 18V6h3l4 8V6h3v12h-3l-4-8v8H7"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v-invert.png
new file mode 100644
index 00000000..ea7e7fd0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v-invert.svg
new file mode 100644
index 00000000..cb1dd893
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v-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="bold-v">
+ <path id="v" d="M10.5 18L6 6h3l3 8 3-8h3l-4.5 12"/>
+ </g>
+</svg>
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
index 146943a5..027db273 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bold-v.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="bold-v">
- <path id="v" d="M10.5 18l-4.5-12h3l3 8 3-8h3l-4.5 12"/>
+ <path id="v" d="M10.5 18L6 6h3l3 8 3-8h3l-4.5 12"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr-invert.png
new file mode 100644
index 00000000..8f8feb61
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr-invert.svg
new file mode 100644
index 00000000..9ff43d35
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-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="M15 7c-1.7 0-3 1.3-3 3 0-1.7-1.3-3-3-3H3v13h6c1.7 0 3 1 3 2 0-1 1.3-2 3-2h6V7h-6zm5 12h-5c-1.7 0-2 .4-2 .4v-8.9C13 9.1 14.1 8 15.5 8H20v11z"/>
+</svg>
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
index 7a058ed3..6a9a7488 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-ltr.svg
@@ -1,4 +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"/>
+ <path d="M15 7c-1.7 0-3 1.3-3 3 0-1.7-1.3-3-3-3H3v13h6c1.7 0 3 1 3 2 0-1 1.3-2 3-2h6V7h-6zm5 12h-5c-1.7 0-2 .4-2 .4v-8.9C13 9.1 14.1 8 15.5 8H20v11z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl-invert.png
new file mode 100644
index 00000000..573fc841
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl-invert.svg
new file mode 100644
index 00000000..93901462
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-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="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-2H3V7h6zM4 19h5c1.7 0 2 .4 2 .4v-8.9C11 9.1 9.9 8 8.5 8H4v11z" id="path78"/>
+</svg>
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
index 6ae47ec5..b192ea6d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/book-rtl.svg
@@ -1,4 +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"/>
+ <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-2H3V7h6zM4 19h5c1.7 0 2 .4 2 .4v-8.9C11 9.1 9.9 8 8.5 8H4v11z" id="path78"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr-invert.png
new file mode 100644
index 00000000..008246c1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr-invert.svg
new file mode 100644
index 00000000..bf39564a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-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="M15 5H8c-1.1 0-2 .9-2 2v3h3v11l4-3 4 3V7c0-1.1-.9-2-2-2zM9 9H7V7c0-.6.4-1 1-1h1v3z"/>
+</svg>
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
index d803d6be..ba3ff91a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-ltr.svg
@@ -1,4 +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"/>
+ <path d="M15 5H8c-1.1 0-2 .9-2 2v3h3v11l4-3 4 3V7c0-1.1-.9-2-2-2zM9 9H7V7c0-.6.4-1 1-1h1v3z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl-invert.png
new file mode 100644
index 00000000..deff3f6c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl-invert.svg
new file mode 100644
index 00000000..f665223a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-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="M8 5h7c1.1 0 2 .9 2 2v3h-3v11l-4-3-4 3V7c0-1.1.9-2 2-2zm6 4h2V7c0-.6-.4-1-1-1h-1v3z" id="path88"/>
+</svg>
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
index 744d0f4e..ba0be744 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bookmark-rtl.svg
@@ -1,4 +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"/>
+ <path d="M8 5h7c1.1 0 2 .9 2 2v3h-3v11l-4-3-4 3V7c0-1.1.9-2 2-2zm6 4h2V7c0-.6-.4-1-1-1h-1v3z" id="path88"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bright.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bright.png
new file mode 100644
index 00000000..3e9e2f1a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bright.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/bright.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bright.svg
new file mode 100644
index 00000000..2717b5a4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/bright.svg
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="Layer_1" 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.9-.3.3-.5.4-.8.4h-2v-1.3zm-6.2-5V2.2c.3 0 .6.1.9.4.3.3.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.3zM6.2 4.9c.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-.4-.3-.3-.4-.5-.4-.8l.1-2zm-7-6.2h2v1.2H3.2c0-.3.1-.6.4-.9.3-.3.5-.3.8-.3zM6.2 16l1.4-1.4.8.8-2.2 2.2c-.2-.2-.3-.5-.3-.8 0-.3.1-.6.3-.8z"/>
+ <g>
+ <path d="M12 8c1.7 0 3 1.3 3 3s-1.3 3-3 3-3-1.3-3-3 1.3-3 3-3m0-1c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4z"/>
+ </g>
+ <path d="M12 8c1.7 0 3 1.3 3 3s-1.3 3-3 3-3-1.3-3-3 1.3-3 3-3m0-1c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr-invert.png
new file mode 100644
index 00000000..4632447b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr-invert.svg
new file mode 100644
index 00000000..762e6418
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-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="M3 6v11c0 1.7 1.3 3 3 3h15V6H3zm2.5 1C6.3 7 7 7.7 7 8.5S6.3 10 5.5 10 4 9.3 4 8.5 4.7 7 5.5 7zM20 19H6c-1.1 0-2-.9-2-2v-6h16v8z"/>
+</svg>
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
index 7bd04250..e7be7e56 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-ltr.svg
@@ -1,4 +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"/>
+ <path d="M3 6v11c0 1.7 1.3 3 3 3h15V6H3zm2.5 1C6.3 7 7 7.7 7 8.5S6.3 10 5.5 10 4 9.3 4 8.5 4.7 7 5.5 7zM20 19H6c-1.1 0-2-.9-2-2v-6h16v8z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl-invert.png
new file mode 100644
index 00000000..5a3df4b3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl-invert.svg
new file mode 100644
index 00000000..b6d0f5c4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-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="M21 6v11c0 1.7-1.3 3-3 3H3V6h18zm-2.5 1c-.8 0-1.5.7-1.5 1.5s.7 1.5 1.5 1.5S20 9.3 20 8.5 19.3 7 18.5 7zM4 19h14c1.1 0 2-.9 2-2v-6H4v8z" id="path98"/>
+</svg>
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
index 84b18dae..080e237c 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/browser-rtl.svg
@@ -1,4 +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"/>
+ <path d="M21 6v11c0 1.7-1.3 3-3 3H3V6h18zm-2.5 1c-.8 0-1.5.7-1.5 1.5s.7 1.5 1.5 1.5S20 9.3 20 8.5 19.3 7 18.5 7zM4 19h14c1.1 0 2-.9 2-2v-6H4v8z" id="path98"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr-invert.png
new file mode 100644
index 00000000..330a53d3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr-invert.svg
new file mode 100644
index 00000000..5eef30c0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-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 5v10c0 1.7 1.3 3 3 3h14V8c0-1.7-1.3-3-3-3H4zm2 1c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zm4 0c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zm4 0c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zm4 0c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zM5 9h3v2H5V9zm4 0h3v2H9V9zm4 0h3v2h-3V9zm4 0h3v2h-3V9zM5 12h3v2H5v-2zm4 0h3v2H9v-2zm4 0h3v2h-3v-2zm4 0h3v2h-3v-2zM5 15h3v2H7c-1.195 0-2-.805-2-2zm4 0h3v2H9v-2zm4 0h3v2h-3v-2zm4 0h3v2h-3v-2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr.png
new file mode 100644
index 00000000..8b3ed72f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-ltr.svg
new file mode 100644
index 00000000..121180e0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-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 5v10c0 1.7 1.3 3 3 3h14V8c0-1.7-1.3-3-3-3H4zm2 1c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zm4 0c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zm4 0c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zm4 0c.552 0 1 .448 1 1s-.448 1-1 1-1-.448-1-1 .448-1 1-1zM5 9h3v2H5V9zm4 0h3v2H9V9zm4 0h3v2h-3V9zm4 0h3v2h-3V9zM5 12h3v2H5v-2zm4 0h3v2H9v-2zm4 0h3v2h-3v-2zm4 0h3v2h-3v-2zM5 15h3v2H7c-1.195 0-2-.805-2-2zm4 0h3v2H9v-2zm4 0h3v2h-3v-2zm4 0h3v2h-3v-2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl-invert.png
new file mode 100644
index 00000000..2f9c5baf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl-invert.svg
new file mode 100644
index 00000000..f7202a98
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-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="M21 5v10c0 1.7-1.3 3-3 3H4V8c0-1.7 1.3-3 3-3h14zm-2 1c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm-4 0c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm-4 0c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zM7 6c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm13 3h-3v2h3V9zm-4 0h-3v2h3V9zm-4 0H9v2h3V9zM8 9H5v2h3V9zm12 3h-3v2h3v-2zm-4 0h-3v2h3v-2zm-4 0H9v2h3v-2zm-4 0H5v2h3v-2zm12 3h-3v2h1c1.195 0 2-.805 2-2zm-4 0h-3v2h3v-2zm-4 0H9v2h3v-2zm-4 0H5v2h3v-2z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl.png
new file mode 100644
index 00000000..8ec5023b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-rtl.svg
new file mode 100644
index 00000000..9b736bf2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/calendar-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 5v10c0 1.7-1.3 3-3 3H4V8c0-1.7 1.3-3 3-3h14zm-2 1c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm-4 0c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm-4 0c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zM7 6c-.552 0-1 .448-1 1s.448 1 1 1 1-.448 1-1-.448-1-1-1zm13 3h-3v2h3V9zm-4 0h-3v2h3V9zm-4 0H9v2h3V9zM8 9H5v2h3V9zm12 3h-3v2h3v-2zm-4 0h-3v2h3v-2zm-4 0H9v2h3v-2zm-4 0H5v2h3v-2zm12 3h-3v2h1c1.195 0 2-.805 2-2zm-4 0h-3v2h3v-2zm-4 0H9v2h3v-2zm-4 0H5v2h3v-2z"/>
+</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
index 5668e127..70dcb874 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.png
+++ 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
index 8a9d3d4d..44cb3ffc 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel-invert.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"><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"/>
+ <path id="circle-with-strike" d="M12 5.022c-3.855 0-6.98 3.124-6.98 6.978 0 3.853 3.124 6.978 6.977 6.978s6.978-3.125 6.978-6.978c0-3.854-3.125-6.978-6.98-6.978zM6.885 12c0-1.092.572-3.25.93-2.93l7.113 7.114c.487.525-1.838.93-2.93.93-2.826 0-5.114-2.29-5.114-5.114zm9.298 2.93L9.07 7.815c-.445-.483 1.837-.93 2.93-.93 2.826 0 5.114 2.288 5.114 5.113 0 1.092-.364 3.542-.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
index 51a33ff8..76b87e46 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.svg
index bfc1b44b..5d0bbd9b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/cancel.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="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"/>
+ <path id="circle-with-strike" d="M12 5.022c-3.855 0-6.98 3.124-6.98 6.978 0 3.853 3.124 6.978 6.977 6.978s6.978-3.125 6.978-6.978c0-3.854-3.125-6.978-6.98-6.978zM6.885 12c0-1.092.572-3.25.93-2.93l7.113 7.114c.487.525-1.838.93-2.93.93-2.826 0-5.114-2.29-5.114-5.114zm9.298 2.93L9.07 7.815c-.445-.483 1.837-.93 2.93-.93 2.826 0 5.114 2.288 5.114 5.113 0 1.092-.364 3.542-.93 2.93z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr-invert.png
new file mode 100644
index 00000000..80488fcd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr-invert.svg
new file mode 100644
index 00000000..b9b6b3a1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-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="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.8L7 13.1z"/>
+</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
index a42aaa5d..d90b3714 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.png
+++ 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
index f31ec095..44d2d1a9 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-ltr.svg
@@ -1,4 +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"/>
+ <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.8L7 13.1z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl-invert.png
new file mode 100644
index 00000000..69eba728
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl-invert.svg
new file mode 100644
index 00000000..bf6087c7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-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="M16.5 13.1L7.6 22c-.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/caret-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.svg
index 02b4e387..88c7c73f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caret-rtl.svg
@@ -1,4 +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"/>
+ <path d="M16.5 13.1L7.6 22c-.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown-invert.png
new file mode 100644
index 00000000..eea3f847
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown-invert.svg
new file mode 100644
index 00000000..dc5d7a11
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown-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 16l8.9-8.9c-.8-.8-2-.8-2.8 0L12 13.2l-6.1-6c-.8-.8-2-.8-2.8 0L12 16z" id="path4"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.svg
index a04ca572..27cb0805 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretDown.svg
@@ -1,4 +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"/>
+ <path d="M12 16l8.9-8.9c-.8-.8-2-.8-2.8 0L12 13.2l-6.1-6c-.8-.8-2-.8-2.8 0L12 16z" id="path4"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp-invert.png
new file mode 100644
index 00000000..7386e143
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp-invert.svg
new file mode 100644
index 00000000..4ca2d5ea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp-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 6.5l8.9 8.9c-.8.8-2 .8-2.8 0L12 9.3l-6.1 6c-.8.8-2 .8-2.8 0L12 6.5z" 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
index 55910950..efd2356b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.png
+++ 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
index d0e0c283..1d630937 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/caretUp.svg
@@ -1,4 +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"/>
+ <path d="M12 6.5l8.9 8.9c-.8.8-2 .8-2.8 0L12 9.3l-6.1 6c-.8.8-2 .8-2.8 0L12 6.5z" id="path4"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive-invert.png
new file mode 100644
index 00000000..212e16d3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive-invert.svg
new file mode 100644
index 00000000..a90feebe
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive-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="regular-expression">
+ <path id="upper-case" d="M7.53 7L4 17h2.063l.72-2.406h3.624l.72 2.406h2.062L9.654 7H7.533zm1.064 1.53L9.938 13H7.25l1.344-4.47z"/>
+ <path id="lower-case" d="M18.55 17l-.184-1.035h-.055c-.35.44-.71.747-1.08.92-.37.167-.85.25-1.443.25-.564 0-.955-.208-1.377-.625-.42-.418-.628-1.012-.628-1.784 0-.808.283-1.403.846-1.784.568-.386 1.193-.607 2.208-.64l1.322-.04v-.335c0-.772-.395-1.158-1.186-1.158-.61 0-1.325.18-2.147.55l-.688-1.4c.877-.46 1.85-.69 2.916-.69 1.024 0 1.59.22 2.134.665.545.445.818 1.12.818 2.03V17h-1.45m-.394-3.527l-.802.027c-.604.018-1.054.127-1.35.327-.294.2-.442.504-.442.912 0 .582.336.874 1.008.874.48 0 .865-.138 1.152-.415.29-.277.436-.645.436-1.103v-.627"/>
+ </g>
+</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
index e30bf2dd..f36e52cb 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.png
+++ 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
index 824790c5..2f0e406d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/case-sensitive.svg
@@ -1,7 +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" />
+ <path id="upper-case" d="M7.53 7L4 17h2.063l.72-2.406h3.624l.72 2.406h2.062L9.654 7H7.533zm1.064 1.53L9.938 13H7.25l1.344-4.47z"/>
+ <path id="lower-case" d="M18.55 17l-.184-1.035h-.055c-.35.44-.71.747-1.08.92-.37.167-.85.25-1.443.25-.564 0-.955-.208-1.377-.625-.42-.418-.628-1.012-.628-1.784 0-.808.283-1.403.846-1.784.568-.386 1.193-.607 2.208-.64l1.322-.04v-.335c0-.772-.395-1.158-1.186-1.158-.61 0-1.325.18-2.147.55l-.688-1.4c.877-.46 1.85-.69 2.916-.69 1.024 0 1.59.22 2.134.665.545.445.818 1.12.818 2.03V17h-1.45m-.394-3.527l-.802.027c-.604.018-1.054.127-1.35.327-.294.2-.442.504-.442.912 0 .582.336.874 1.008.874.48 0 .865-.138 1.152-.415.29-.277.436-.645.436-1.103v-.627"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-destructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-destructive.png
new file mode 100644
index 00000000..9577504b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-destructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-destructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-destructive.svg
new file mode 100644
index 00000000..7e09e65b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/check-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="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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg
index 085e6677..f1291f94 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-constructive.svg
@@ -1,2 +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: #00AF89 }</style><circle cx="12" cy="12" r="6"></circle></svg>
+<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"/>
+</svg>
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
index f5285c73..7cae5db2 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle-invert.svg
@@ -1,2 +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><circle cx="12" cy="12" r="6"></circle></svg>
+<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"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg
index 436259e5..18133cc9 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/circle.svg
@@ -1,2 +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"><circle cx="12" cy="12" r="6"></circle></svg>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <circle cx="12" cy="12" r="6"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr-invert.png
new file mode 100644
index 00000000..08a5fe10
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr-invert.svg
new file mode 100644
index 00000000..bdb38237
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-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="M7 12h9v-1H7v1zm0 2h9v-1H7v1zm0 2h9v-1H7v1zm4-9H7v1h4V7zm0 2H7v1h4V9zm0-4H7v1h4V5zm5-2h2v16H8c-1.7 0-3-1.3-3-3V3h8v7l1.5-2 1.5 2V3z"/>
+ </g>
+</svg>
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
index 28ba0cb5..d997cf2e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-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>
- <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"/>
+ <path d="M7 12h9v-1H7v1zm0 2h9v-1H7v1zm0 2h9v-1H7v1zm4-9H7v1h4V7zm0 2H7v1h4V9zm0-4H7v1h4V5zm5-2h2v16H8c-1.7 0-3-1.3-3-3V3h8v7l1.5-2 1.5 2V3z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl-invert.png
new file mode 100644
index 00000000..af33ec0d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl-invert.svg
new file mode 100644
index 00000000..19574773
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-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="g128">
+ <path d="M16 12H7v-1h9v1zm0 2H7v-1h9v1zm0 2H7v-1h9v1zm-4-9h4v1h-4V7zm0 2h4v1h-4V9zm0-4h4v1h-4V5zM7 3H5v16h10c1.7 0 3-1.3 3-3V3h-8v7L8.5 8 7 10V3z" id="path130"/>
+ </g>
+</svg>
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
index 7625307c..688bd1be 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/citeArticle-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="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"/>
+ <path d="M16 12H7v-1h9v1zm0 2H7v-1h9v1zm0 2H7v-1h9v1zm-4-9h4v1h-4V7zm0 2h4v1h-4V9zm0-4h4v1h-4V5zM7 3H5v16h10c1.7 0 3-1.3 3-3V3h-8v7L8.5 8 7 10V3z" id="path130"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear-invert.png
new file mode 100644
index 00000000..d8b538e9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear-invert.svg
new file mode 100644
index 00000000..07382052
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear-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="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/clear.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.svg
index 55a26c97..8689e770 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clear.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">
- <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>
+ <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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock-invert.png
new file mode 100644
index 00000000..2ac138b1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock-invert.svg
new file mode 100644
index 00000000..96826261
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock-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="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-3V8h2v5l1.7 1.2c1.3.9 1 1.9.3 2.8z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.svg
index 1cf72670..6d8f75e1 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/clock.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>
- <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"/>
+ <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-3V8h2v5l1.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
index 6d8abc3b..32d5ae82 100644
--- 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
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
index ec44c925..cd7ce218 100644
--- 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
@@ -1,4 +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>
- <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"/>
+ <g id="close">
+ <path id="cross" d="M17.4 9.1c.8-.8.8-2 0-2.8L12 11.8 7.4 7.2 6 8.6l4.6 4.6-4 4c-.8.8-.8 2 0 2.8l5.4-5.4 4.6 4.6 1.4-1.4-4.6-4.6z"/>
+ </g>
</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
index ea65697c..b05cc973 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.png
+++ 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
index 4f0f64ec..1427670d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-ltr.svg
@@ -1,4 +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">
- <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"/>
+ <g id="close">
+ <path id="cross" d="M17.4 9.1c.8-.8.8-2 0-2.8L12 11.8 7.4 7.2 6 8.6l4.6 4.6-4 4c-.8.8-.8 2 0 2.8l5.4-5.4 4.6 4.6 1.4-1.4-4.6-4.6z"/>
+ </g>
</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
index 004a5186..731baf99 100644
--- 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
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
index b5ae392f..ee8a82d3 100644
--- 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
@@ -1,4 +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>
- <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"/>
+ <g id="close">
+ <path id="cross" d="M6.6 9.1c-.8-.8-.8-2 0-2.8l5.4 5.5 4.6-4.6L18 8.6l-4.6 4.6 4 4c.8.8.8 2 0 2.8L12 14.6l-4.6 4.6L6 17.8l4.6-4.6z"/>
+ </g>
</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
index 1cb898d1..37525201 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.png
+++ 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
index d9829d0e..6e0ca937 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/close-rtl.svg
@@ -1,4 +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">
- <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"/>
+ <g id="close">
+ <path id="cross" d="M6.6 9.1c-.8-.8-.8-2 0-2.8l5.4 5.5 4.6-4.6L18 8.6l-4.6 4.6 4 4c.8.8.8 2 0 2.8L12 14.6l-4.6 4.6L6 17.8l4.6-4.6z"/>
+ </g>
</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
index 23c59835..97e0c2c5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.png
+++ 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
index bc4ae943..d62d2301 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code-invert.svg
@@ -1,7 +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"/>
+ <path id="left-bracket" d="M4 12v-1h1c1 0 1 0 1-1V7.614c0-.514.024-.896.073-1.142.054-.252.14-.463.257-.633.204-.28.473-.48.808-.588C7.473 5.14 8.01 5 8.973 5H10v1h-.752c-.457 0-.77.19-.936.408C8.145 6.623 8 6.853 8 7.476v1.857c0 .73-.04 1.18-.244 1.493-.2.307-.562.53-1.09.667.535.155.9.385 1.096.688.2.307.238.76.238 1.488v1.862c0 .62.145.847.312 1.06.166.22.48.407.936.407L10 17v1H8.973c-.963 0-1.5-.133-1.835-.248-.335-.11-.604-.307-.808-.59-.118-.166-.203-.375-.257-.626-.05-.253-.073-.636-.073-1.15V13c0-1 0-1-1-1H4z"/>
<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
index ee58c9a7..6e678e2a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.svg
index 32f140d9..d3893b0f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/code.svg
@@ -1,7 +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">
<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"/>
+ <path id="left-bracket" d="M4 12v-1h1c1 0 1 0 1-1V7.614c0-.514.024-.896.073-1.142.054-.252.14-.463.257-.633.204-.28.473-.48.808-.588C7.473 5.14 8.01 5 8.973 5H10v1h-.752c-.457 0-.77.19-.936.408C8.145 6.623 8 6.853 8 7.476v1.857c0 .73-.04 1.18-.244 1.493-.2.307-.562.53-1.09.667.535.155.9.385 1.096.688.2.307.238.76.238 1.488v1.862c0 .62.145.847.312 1.06.166.22.48.407.936.407L10 17v1H8.973c-.963 0-1.5-.133-1.835-.248-.335-.11-.604-.307-.808-.59-.118-.166-.203-.375-.257-.626-.05-.253-.073-.636-.073-1.15V13c0-1 0-1-1-1H4z"/>
<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/collapse-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.png
index a9d0d33b..3e7e9931 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.png
+++ 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
index 451e0fee..926f98d7 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse-invert.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"><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"/>
+ <path id="arrow" d="M6.697 15.714L12 10.412l5.303 5.302 1.414-1.414L12 7.583 5.283 14.3z"/>
</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
index 353ac798..4dad20f4 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/collapse.svg
index 55aa8f8f..645bfda5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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">
- <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"/>
+ <path id="arrow" d="M6.697 15.714L12 10.412l5.303 5.302 1.414-1.414L12 7.583 5.283 14.3z"/>
</g>
</svg>
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
index b6152fe9..3b58d71b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment-invert.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"><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"/>
+ <path id="speech-bubble" d="M15 6H9C7.343 6 6 7.344 6 9v4c0 1.656 1.343 3 3 3v3l3-3h3c1.657 0 3-1.344 3-3V9c0-1.656-1.343-3-3-3z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/comment.svg
index 0ae7e63f..c52ce1c1 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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">
- <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"/>
+ <path id="speech-bubble" d="M15 6H9C7.343 6 6 7.344 6 9v4c0 1.656 1.343 3 3 3v3l3-3h3c1.657 0 3-1.344 3-3V9c0-1.656-1.343-3-3-3z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr-invert.png
new file mode 100644
index 00000000..add46d47
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr-invert.svg
new file mode 100644
index 00000000..8bac842c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-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="M16 5H4v12c0 1.6 1.3 3 3 3h12V8c0-1.7-1.4-3-3-3zM7.5 17c-.8 0-1.5-.7-1.5-1.5S6.7 14 7.5 14s1.5.7 1.5 1.5S8.3 17 7.5 17zm0-6C6.7 11 6 10.3 6 9.5S6.7 8 7.5 8 9 8.7 9 9.5 8.3 11 7.5 11zm4 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.5S14.7 8 15.5 8s1.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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.svg
index eb4c360d..2571d4dc 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-ltr.svg
@@ -1,4 +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"/>
+ <path d="M16 5H4v12c0 1.6 1.3 3 3 3h12V8c0-1.7-1.4-3-3-3zM7.5 17c-.8 0-1.5-.7-1.5-1.5S6.7 14 7.5 14s1.5.7 1.5 1.5S8.3 17 7.5 17zm0-6C6.7 11 6 10.3 6 9.5S6.7 8 7.5 8 9 8.7 9 9.5 8.3 11 7.5 11zm4 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.5S14.7 8 15.5 8s1.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl-invert.png
new file mode 100644
index 00000000..2ecf9138
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl-invert.svg
new file mode 100644
index 00000000..d6a74cfc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-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="M7 5h12v12c0 1.6-1.3 3-3 3H4V8c0-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.5S16.3 8 15.5 8 14 8.7 14 9.5s.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.5S8.3 14 7.5 14 6 14.7 6 15.5 6.7 17 7.5 17zm0-6c.8 0 1.5-.7 1.5-1.5S8.3 8 7.5 8 6 8.7 6 9.5 6.7 11 7.5 11z" id="path150"/>
+</svg>
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
index e929fdb1..1b4a6ca1 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/die-rtl.svg
@@ -1,4 +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"/>
+ <path d="M7 5h12v12c0 1.6-1.3 3-3 3H4V8c0-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.5S16.3 8 15.5 8 14 8.7 14 9.5s.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.5S8.3 14 7.5 14 6 14.7 6 15.5 6.7 17 7.5 17zm0-6c.8 0 1.5-.7 1.5-1.5S8.3 8 7.5 8 6 8.7 6 9.5 6.7 11 7.5 11z" id="path150"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle-invert.png
new file mode 100644
index 00000000..b87c9778
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle-invert.svg
new file mode 100644
index 00000000..d18ef8bb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle-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 18l8-10H4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.svg
index 7bc1c228..e1fb989c 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/downTriangle.svg
@@ -1,4 +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"/>
+ <path d="M12 18l8-10H4z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr-invert.png
new file mode 100644
index 00000000..1e2f6c9e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr-invert.svg
new file mode 100644
index 00000000..e23e7738
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-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="M16 11h-3V4c-1.7 0-3 1.3-3 3v4H7l4.5 5 4.5-5zm1 2v5H7c-.6 0-1-.4-1-1v-4H4v4c0 1.9 1.3 3 3 3h12v-7h-2z"/>
+ </g>
+</svg>
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
index d0d5bb5b..ba378482 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-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>
- <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"/>
+ <path d="M16 11h-3V4c-1.7 0-3 1.3-3 3v4H7l4.5 5 4.5-5zm1 2v5H7c-.6 0-1-.4-1-1v-4H4v4c0 1.9 1.3 3 3 3h12v-7h-2z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl-invert.png
new file mode 100644
index 00000000..167fd8d6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl-invert.svg
new file mode 100644
index 00000000..64096318
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-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="g160">
+ <path d="M7 11h3V4c1.7 0 3 1.3 3 3v4h3l-4.5 5L7 11zm-1 2v5h10c.6 0 1-.4 1-1v-4h2v4c0 1.9-1.3 3-3 3H4v-7h2z" id="path162"/>
+ </g>
+</svg>
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
index 9abb2ae4..544c3c80 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/download-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="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"/>
+ <path d="M7 11h3V4c1.7 0 3 1.3 3 3v4h3l-4.5 5L7 11zm-1 2v5h10c.6 0 1-.4 1-1v-4h2v4c0 1.9-1.3 3-3 3H4v-7h2z" id="path162"/>
</g>
</svg>
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
index add25a45..fbae9d2b 100644
--- 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
@@ -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"><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"/>
+ <path d="M17 2L5 14l-1 5 5-1L21 6c0-2-2-4-4-4zM7.2 15.5c-.3-.3-.7-.6-1-.8C8.5 12.4 17.5 3.3 17.5 3.3c.4.1.7.3 1 .7L7.2 15.5z"/>
</g>
</svg>
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
index bceb7c16..d27c3a58 100644
--- 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
@@ -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"><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"/>
+ <path d="M17 2L5 14l-1 5 5-1L21 6c0-2-2-4-4-4zM7.2 15.5c-.3-.3-.7-.6-1-.8C8.5 12.4 17.5 3.3 17.5 3.3c.4.1.7.3 1 .7L7.2 15.5z"/>
</g>
</svg>
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
index 3972e070..4cd6cdac 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-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="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"/>
+ <path d="M17 2L5 14l-1 5 5-1L21 6c0-2-2-4-4-4zM7.2 15.5c-.3-.3-.7-.6-1-.8C8.5 12.4 17.5 3.3 17.5 3.3c.4.1.7.3 1 .7L7.2 15.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
index 2b311a9c..c66c5fd0 100644
--- 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
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
index 339c8309..42c9f2c1 100644
--- 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
@@ -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"><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"/>
+ <path d="M8 2l12 12 1 5-5-1L4 6c0-2 2-4 4-4zm9.8 13.5c.3-.3.7-.6 1-.8C16.5 12.4 7.5 3.3 7.5 3.3c-.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
index 8d36fa8a..ef6c949a 100644
--- 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
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
index d526fb4c..b4db76b3 100644
--- 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
@@ -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"><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"/>
+ <path d="M8 2l12 12 1 5-5-1L4 6c0-2 2-4 4-4zm9.8 13.5c.3-.3.7-.6 1-.8C16.5 12.4 7.5 3.3 7.5 3.3c-.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
index 4750795c..47559372 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.png
+++ 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
index 978b2fd1..932997b1 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/edit-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="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"/>
+ <path d="M8 2l12 12 1 5-5-1L4 6c0-2 2-4 4-4zm9.8 13.5c.3-.3.7-.6 1-.8C16.5 12.4 7.5 3.3 7.5 3.3c-.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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr-invert.svg
index 30d10218..774d15aa 100644
--- 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
@@ -2,7 +2,7 @@
<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"/>
+ <path d="M21 4V3s0-3-3-3-3 3-3 3v1h-1v6h8V4zm-1.5 0h-3V3s0-1.5 1.5-1.5c1.48.06 1.5 1.5 1.5 1.5zM13 9.6l-6.8 6.9c-.3-.3-.7-.6-1-.8 1.4-1.4 5-5 7.8-7.9V6l-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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.svg
index 7e376824..1b1cb76e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-ltr.svg
@@ -2,7 +2,7 @@
<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"/>
+ <path d="M21 4V3s0-3-3-3-3 3-3 3v1h-1v6h8V4zm-1.5 0h-3V3s0-1.5 1.5-1.5c1.48.06 1.5 1.5 1.5 1.5zM13 9.6l-6.8 6.9c-.3-.3-.7-.6-1-.8 1.4-1.4 5-5 7.8-7.9V6l-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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl-invert.svg
index 0e975b59..2908444f 100644
--- 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
@@ -2,7 +2,7 @@
<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"/>
+ <path d="M4 4V3s0-3 3-3 3 3 3 3v1h1v6H3V4zm1.5 0h3V3s0-1.5-1.5-1.5C5.52 1.56 5.5 3 5.5 3zM12 9.6l6.8 6.9c.3-.3.7-.6 1-.8-1.4-1.4-5-5-7.8-7.9V6l9 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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.svg
index 0b4751d2..84a68164 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editLock-rtl.svg
@@ -2,7 +2,7 @@
<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"/>
+ <path d="M4 4V3s0-3 3-3 3 3 3 3v1h1v6H3V4zm1.5 0h3V3s0-1.5-1.5-1.5C5.52 1.56 5.5 3 5.5 3zM12 9.6l6.8 6.9c.3-.3.7-.6 1-.8-1.4-1.4-5-5-7.8-7.9V6l9 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
index 3952442e..19774770 100644
--- 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
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
index cc8b61f6..5d720f4e 100644
--- 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
@@ -2,10 +2,10 @@
<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"/>
+ <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-.3L8 3l1.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"/>
+ <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.8H9.1L5 15l-1 5 5-1 7.8-7.8-1.6-.1zM20.6 6c-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
index fe8631ea..e3dc95a2 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.png
+++ 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
index f346874e..05778cd8 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-ltr.svg
@@ -2,10 +2,10 @@
<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"/>
+ <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-.3L8 3l1.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"/>
+ <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.8H9.1L5 15l-1 5 5-1 7.8-7.8-1.6-.1zM20.6 6c-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
index 53469ce9..9070cab6 100644
--- 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
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
index 82018f0b..8323c2f0 100644
--- 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
@@ -2,10 +2,10 @@
<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"/>
+ <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-.3L17 3l-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"/>
+ <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.8L20 15l1 5-5-1-7.8-7.8 1.6-.1zM4.4 6c1.7 0 3.2.5 4.4 1.4l.9.9-.8 1.3L8 11 4 7c0-.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
index ca5596ee..6dd8b464 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.png
+++ 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
index 5b59d452..ac03c05a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/editUndo-rtl.svg
@@ -2,10 +2,10 @@
<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"/>
+ <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-.3L17 3l-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"/>
+ <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.8L20 15l1 5-5-1-7.8-7.8 1.6-.1zM4.4 6c1.7 0 3.2.5 4.4 1.4l.9.9-.8 1.3L8 11 4 7c0-.3.1-.7.2-1h.2z" id="path206"/>
</g>
</svg>
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
index a3cadb48..21f80da6 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand-invert.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"><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"/>
+ <path id="arrow" d="M17.303 8.283L12 13.586 6.697 8.283 5.283 9.697 12 16.414l6.717-6.717z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/expand.svg
index 7666b41d..84b9e0a6 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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">
- <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"/>
+ <path id="arrow" d="M17.303 8.283L12 13.586 6.697 8.283 5.283 9.697 12 16.414l6.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
index 3be50ba0..eec31027 100644
--- 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
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
index c1bad9e6..0526f75b 100644
--- 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
@@ -1,7 +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>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><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"/>
+ <path id="box" d="M4 4h6v2H6v12h12v-4h2v6H4z"/>
+ <path id="arrow" d="M12.42 4H20v7.58l-2.84-2.846L12.892 13 11 11.106l4.264-4.266z"/>
</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
index 10927e16..4b59b2a2 100644
--- 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
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
index 827bc1b1..1d7980dc 100644
--- 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
@@ -1,7 +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">
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<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"/>
+ <path id="box" d="M4 4h6v2H6v12h12v-4h2v6H4z"/>
+ <path id="arrow" d="M12.42 4H20v7.58l-2.84-2.846L12.892 13 11 11.106l4.264-4.266z"/>
</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
index eaeaf6ee..bf0ef139 100644
--- 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
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
index f448c879..d747aa68 100644
--- 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
@@ -1,7 +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>
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><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"/>
+ <path id="box" d="M20 4h-6v2h4v12H6v-4H4v6h16z"/>
+ <path id="arrow" d="M11.58 4H4v7.58l2.84-2.846L11.108 13 13 11.106 8.736 6.84z"/>
</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
index 7a3454e9..29786548 100644
--- 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
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
index c375ca0f..7e25d034 100644
--- 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
@@ -1,7 +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">
+<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
<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"/>
+ <path id="box" d="M20 4h-6v2h4v12H6v-4H4v6h16z"/>
+ <path id="arrow" d="M11.58 4H4v7.58l2.84-2.846L11.108 13 13 11.106 8.736 6.84z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye-invert.png
new file mode 100644
index 00000000..84a838b8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye-invert.svg
new file mode 100644
index 00000000..352e7b92
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye-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="g4">
+ <path d="M12 8C7 8 1 14 1 14s6 6 11 6l11-6s-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/eye.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.png
index 26accd8c..f8515918 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.png
+++ 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
index fa3bc3c1..09d783b7 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eye.svg
@@ -1,7 +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"/>
+ <path d="M12 8C7 8 1 14 1 14s6 6 11 6l11-6s-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed-invert.png
new file mode 100644
index 00000000..7b4bb154
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed-invert.svg
new file mode 100644
index 00000000..d8f7dff9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed-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="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.6H2.2c.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/eyeClosed.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.png
index 301bf8cb..f350b575 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.png
+++ 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
index fa1167df..d17f2c8a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/eyeClosed.svg
@@ -1,4 +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"/>
+ <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.6H2.2c.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr-invert.png
new file mode 100644
index 00000000..010b224b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr-invert.svg
new file mode 100644
index 00000000..5764ee6d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr-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="find">
+ <path id="magnifying-glass" d="M13.656 11c-1.92 0-3.5 1.548-3.5 3.47 0 1.92 1.58 3.5 3.5 3.5.75 0 1.432-.253 2-.657l.094.156 2.375 2.37c.19.19.534.154.78-.093s.315-.59.126-.78l-2.37-2.377-.188-.093c.402-.567.655-1.283.655-2.03 0-1.92-1.55-3.47-3.47-3.47zm0 1.656c1.01 0 1.813.8 1.813 1.813 0 1.01-.805 1.84-1.817 1.84-1.01 0-1.844-.83-1.844-1.844s.832-1.814 1.844-1.814z"/>
+ <path id="text" d="M6 5v2h10V5H6zm0 3v2h11V8H6zm0 3v2h3.53c.284-.797.787-1.486 1.44-2H6zm0 3v2h3.53c-.177-.48-.28-.99-.28-1.53 0-.16.046-.315.063-.47H6z"/>
+ </g>
+</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
index 4336892a..9f418b88 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.png
+++ 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
index f8578cf8..67e69434 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-ltr.svg
@@ -1,7 +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" />
+ <path id="magnifying-glass" d="M13.656 11c-1.92 0-3.5 1.548-3.5 3.47 0 1.92 1.58 3.5 3.5 3.5.75 0 1.432-.253 2-.657l.094.156 2.375 2.37c.19.19.534.154.78-.093s.315-.59.126-.78l-2.37-2.377-.188-.093c.402-.567.655-1.283.655-2.03 0-1.92-1.55-3.47-3.47-3.47zm0 1.656c1.01 0 1.813.8 1.813 1.813 0 1.01-.805 1.84-1.817 1.84-1.01 0-1.844-.83-1.844-1.844s.832-1.814 1.844-1.814z"/>
+ <path id="text" d="M6 5v2h10V5H6zm0 3v2h11V8H6zm0 3v2h3.53c.284-.797.787-1.486 1.44-2H6zm0 3v2h3.53c-.177-.48-.28-.99-.28-1.53 0-.16.046-.315.063-.47H6z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl-invert.png
new file mode 100644
index 00000000..4a70b137
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl-invert.svg
new file mode 100644
index 00000000..68545535
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl-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="find">
+ <path id="magnifying-glass" d="M11.344 11c1.92 0 3.5 1.548 3.5 3.47 0 1.92-1.58 3.5-3.5 3.5-.75 0-1.432-.253-2-.657l-.094.156-2.375 2.37c-.19.19-.534.154-.78-.093s-.315-.59-.126-.78l2.37-2.377.188-.093c-.402-.567-.655-1.283-.655-2.03 0-1.92 1.55-3.47 3.47-3.47zm0 1.656c-1.01 0-1.813.8-1.813 1.813 0 1.01.805 1.84 1.817 1.84 1.01 0 1.844-.83 1.844-1.844s-.832-1.814-1.844-1.814z"/>
+ <path id="text" d="M19 5v2H9V5zm0 3v2H8V8zm0 3v2h-3.53c-.284-.797-.787-1.486-1.44-2zm0 3v2h-3.53c.177-.48.28-.99.28-1.53 0-.16-.046-.315-.063-.47z"/>
+ </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
index f492c791..b63eb841 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.png
+++ 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
index 2a1e9c6f..962165d6 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/find-rtl.svg
@@ -1,7 +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" />
+ <path id="magnifying-glass" d="M11.344 11c1.92 0 3.5 1.548 3.5 3.47 0 1.92-1.58 3.5-3.5 3.5-.75 0-1.432-.253-2-.657l-.094.156-2.375 2.37c-.19.19-.534.154-.78-.093s-.315-.59-.126-.78l2.37-2.377.188-.093c-.402-.567-.655-1.283-.655-2.03 0-1.92 1.55-3.47 3.47-3.47zm0 1.656c-1.01 0-1.813.8-1.813 1.813 0 1.01.805 1.84 1.817 1.84 1.01 0 1.844-.83 1.844-1.844s-.832-1.814-1.844-1.814z"/>
+ <path id="text" d="M19 5v2H9V5zm0 3v2H8V8zm0 3v2h-3.53c-.284-.797-.787-1.486-1.44-2zm0 3v2h-3.53c.177-.48.28-.99.28-1.53 0-.16-.046-.315-.063-.47z"/>
</g>
</svg>
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
index 37ddb247..964d551b 100644
--- 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
@@ -1,4 +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"/>
+ <path d="M14 6.5V5c-1.4-1.5-5.2-1.2-6 0V4H7v15h1v-7c.8-.8 3.4-.9 5-.5V13c1.2 1.5 4.3 1.2 5 0V6c-.7.7-2.7.9-4 .5z" id="path216"/>
</svg>
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
index 6e81d2bc..bcd728ec 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-ltr.svg
@@ -1,4 +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"/>
+ <path d="M14 6.5V5c-1.4-1.5-5.2-1.2-6 0V4H7v15h1v-7c.8-.8 3.4-.9 5-.5V13c1.2 1.5 4.3 1.2 5 0V6c-.7.7-2.7.9-4 .5z" id="path216"/>
</svg>
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
index 4875a443..4996fe01 100644
--- 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
@@ -1,4 +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"/>
+ <path d="M11 6.5V5c1.4-1.5 5.2-1.2 6 0V4h1v15h-1v-7c-.8-.8-3.4-.9-5-.5V13c-1.2 1.5-4.3 1.2-5 0V6c.7.7 2.7.9 4 .5z" id="path216"/>
</svg>
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
index 4b743aac..3a93b6f7 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flag-rtl.svg
@@ -1,4 +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"/>
+ <path d="M11 6.5V5c1.4-1.5 5.2-1.2 6 0V4h1v15h-1v-7c-.8-.8-3.4-.9-5-.5V13c-1.2 1.5-4.3 1.2-5 0V6c.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
index fd7f2ae8..9ef05523 100644
--- 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
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
index dcea1eb7..5b1c8cdc 100644
--- 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
@@ -2,14 +2,14 @@
<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"/>
+ <path id="path227" d="M14 6.5V5c-1.4-1.5-5.2-1.2-6 0V4H7v15h1v-7c.8-.8 3.4-.9 5-.5V13c1.2 1.5 4.3 1.2 5 0V6c-.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"/>
+ <path id="path232" d="M17.997 1.99l.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"/>
+ <path id="path236" d="M17 1.016l.99.99-15.98 15.98-.99-.99z" fill="#fff"/>
</g>
</g>
</g>
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
index fff89fe8..6f84122e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.png
+++ 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
index 49cdb7a2..87245de9 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-ltr.svg
@@ -2,14 +2,14 @@
<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"/>
+ <path id="path227" d="M14 6.5V5c-1.4-1.5-5.2-1.2-6 0V4H7v15h1v-7c.8-.8 3.4-.9 5-.5V13c1.2 1.5 4.3 1.2 5 0V6c-.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"/>
+ <path id="path232" d="M17.997 1.99l.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"/>
+ <path id="path236" d="M17 1.016l.99.99-15.98 15.98-.99-.99z" fill="#fff"/>
</g>
</g>
</g>
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
index d6ffceaa..52164697 100644
--- 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
@@ -2,14 +2,14 @@
<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"/>
+ <path id="path227" d="M11 6.5V5c1.4-1.5 5.2-1.2 6 0V4h1v15h-1v-7c-.8-.8-3.4-.9-5-.5V13c-1.2 1.5-4.3 1.2-5 0V6c.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"/>
+ <path id="path232" d="M7.003 1.99l-.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"/>
+ <path id="path236" d="M8 1.016l-.99.99 15.98 15.98.99-.99z" fill="#fff"/>
</g>
</g>
</g>
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
index e470de42..06da23a6 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/flagUndo-rtl.svg
@@ -2,14 +2,14 @@
<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"/>
+ <path id="path227" d="M11 6.5V5c1.4-1.5 5.2-1.2 6 0V4h1v15h-1v-7c-.8-.8-3.4-.9-5-.5V13c-1.2 1.5-4.3 1.2-5 0V6c.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"/>
+ <path id="path232" d="M7.003 1.99l-.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"/>
+ <path id="path236" d="M8 1.016l-.99.99 15.98 15.98.99-.99z" fill="#fff"/>
</g>
</g>
</g>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr-invert.png
new file mode 100644
index 00000000..5c9d194f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr-invert.svg
new file mode 100644
index 00000000..7dfc979d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-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="M2 5v15h20V5H2zm15 11H8c-.6 0-1-.4-1-1V9h3l2 1h5v6z"/>
+</svg>
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
index 63e0b1aa..7e60fb4b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-ltr.svg
@@ -1,4 +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"/>
+ <path d="M2 5v15h20V5H2zm15 11H8c-.6 0-1-.4-1-1V9h3l2 1h5v6z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl-invert.png
new file mode 100644
index 00000000..9fd77b23
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl-invert.svg
new file mode 100644
index 00000000..a384bd17
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-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="M22 5v15H2V5h20zM7 16h9c.6 0 1-.4 1-1V9h-3l-2 1H7v6z" id="path246"/>
+</svg>
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
index 25bec742..29f5c6b5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/folderPlaceholder-rtl.svg
@@ -1,4 +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"/>
+ <path d="M22 5v15H2V5h20zM7 16h9c.6 0 1-.4 1-1V9h-3l-2 1H7v6z" id="path246"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr-invert.png
new file mode 100644
index 00000000..056e7814
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr-invert.svg
new file mode 100644
index 00000000..3ea25f40
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-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="M11 13L5 6h15l-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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.svg
index 191584eb..8d5bf448 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-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>
- <path d="M11 13l-6-7h15l-6 7v7c-1.7 0-3-1.3-3-3v-4z"/>
+ <path d="M11 13L5 6h15l-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl-invert.png
new file mode 100644
index 00000000..7d4f60ae
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl-invert.svg
new file mode 100644
index 00000000..1fa603f8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-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="g256">
+ <path d="M14 13l6-7H5l6 7v7c1.7 0 3-1.3 3-3v-4z" id="path258"/>
+ </g>
+</svg>
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
index 45f2f642..ec54b1ba 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/funnel-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="g256">
- <path d="M14 13l6-7h-15l6 7v7c1.7 0 3-1.3 3-3v-4z" id="path258"/>
+ <path d="M14 13l6-7H5l6 7v7c1.7 0 3-1.3 3-3v-4z" id="path258"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/halfBright.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/halfBright.png
new file mode 100644
index 00000000..9332beae
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/halfBright.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/halfBright.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/halfBright.svg
new file mode 100644
index 00000000..fff92e74
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/halfBright.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M11.4 5.4V2.2c.3 0 .6.1.9.4.3.3.4.5.4.8v2h-1.3zm-5.2-.5c.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-.4-.3-.3-.4-.5-.4-.8l.1-2zm-7-6.2h2v1.2H3.2c0-.3.1-.6.4-.9.3-.3.5-.3.8-.3zM6.2 16l1.4-1.4.8.8-2.2 2.2c-.2-.2-.3-.5-.3-.8 0-.3.1-.6.3-.8zM12 7c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4zm-3 4c0-1.7 1.3-3 3-3v6c-1.7 0-3-1.3-3-3z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart-invert.png
new file mode 100644
index 00000000..b6313968
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart-invert.svg
new file mode 100644
index 00000000..fc782264
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/heart-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="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
index 185c1a27..ac9968d6 100644
--- 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
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
index 3670661a..fdefd972 100644
--- 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
@@ -1,9 +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="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"/>
+ <path id="circle" d="M12 2.085c-5.477 0-9.915 4.438-9.915 9.916 0 5.48 4.438 9.918 9.916 9.918 5.48 0 9.918-4.438 9.918-9.914 0-5.477-4.438-9.915-9.914-9.915zm.002 18c-4.465 0-8.084-3.62-8.084-8.083 0-4.465 3.62-8.084 8.084-8.084 4.464 0 8.083 3.62 8.083 8.084 0 4.464-3.62 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="top" d="M11.766 6.688c-2.5 0-3.22 2.188-3.22 2.188l1.412.854s.298-.79.9-1.23c.517-.374 1.626-.624 2.22.126.7.885-.17 1.587-1.078 2.72C11.047 12.53 11 15 11 15h1.97s.134-2.318 1.04-3.38c.603-.708 1.443-1.34 1.443-2.495s-1.187-2.437-3.687-2.437z"/>
<path id="bottom" d="M11 16h2v2h-2z"/>
</g>
</g>
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
index b80df009..4428ef32 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.svg
index bb2545c5..825435da 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-ltr.svg
@@ -1,9 +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="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"/>
+ <path id="circle" d="M12 2.085c-5.477 0-9.915 4.438-9.915 9.916 0 5.48 4.438 9.918 9.916 9.918 5.48 0 9.918-4.438 9.918-9.914 0-5.477-4.438-9.915-9.914-9.915zm.002 18c-4.465 0-8.084-3.62-8.084-8.083 0-4.465 3.62-8.084 8.084-8.084 4.464 0 8.083 3.62 8.083 8.084 0 4.464-3.62 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="top" d="M11.766 6.688c-2.5 0-3.22 2.188-3.22 2.188l1.412.854s.298-.79.9-1.23c.517-.374 1.626-.624 2.22.126.7.885-.17 1.587-1.078 2.72C11.047 12.53 11 15 11 15h1.97s.134-2.318 1.04-3.38c.603-.708 1.443-1.34 1.443-2.495s-1.187-2.437-3.687-2.437z"/>
<path id="bottom" d="M11 16h2v2h-2z"/>
</g>
</g>
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
index dfb9c031..f425c359 100644
--- 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
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
index 203f8f9b..b3698138 100644
--- 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
@@ -1,9 +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="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"/>
+ <path id="circle" d="M12 2.085c5.477 0 9.915 4.438 9.915 9.916 0 5.48-4.438 9.918-9.916 9.918-5.48 0-9.918-4.438-9.918-9.914 0-5.477 4.438-9.915 9.914-9.915zm-.002 18c4.465 0 8.084-3.62 8.084-8.083 0-4.465-3.62-8.084-8.084-8.084-4.464 0-8.083 3.62-8.083 8.084 0 4.464 3.62 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="top" d="M12.234 6.688c2.5 0 3.22 2.188 3.22 2.188l-1.412.854s-.298-.79-.9-1.23c-.517-.374-1.626-.624-2.22.126-.7.885.17 1.587 1.078 2.72C12.953 12.53 13 15 13 15h-1.97s-.134-2.318-1.04-3.38c-.603-.708-1.443-1.34-1.443-2.495 0-1.156 1.187-2.437 3.687-2.437z"/>
<path id="bottom" d="M13 16h-2v2h2z"/>
</g>
</g>
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
index 62f3d21a..e6ab21be 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.png
+++ 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
index 99c7f842..0d8052f1 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/help-rtl.svg
@@ -1,9 +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="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"/>
+ <path id="circle" d="M12 2.085c5.477 0 9.915 4.438 9.915 9.916 0 5.48-4.438 9.918-9.916 9.918-5.48 0-9.918-4.438-9.918-9.914 0-5.477 4.438-9.915 9.914-9.915zm-.002 18c4.465 0 8.084-3.62 8.084-8.083 0-4.465-3.62-8.084-8.084-8.084-4.464 0-8.083 3.62-8.083 8.084 0 4.464 3.62 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="top" d="M12.234 6.688c2.5 0 3.22 2.188 3.22 2.188l-1.412.854s-.298-.79-.9-1.23c-.517-.374-1.626-.624-2.22.126-.7.885.17 1.587 1.078 2.72C12.953 12.53 13 15 13 15h-1.97s-.134-2.318-1.04-3.38c-.603-.708-1.443-1.34-1.443-2.495 0-1.156 1.187-2.437 3.687-2.437z"/>
<path id="bottom" d="M13 16h-2v2h2z"/>
</g>
</g>
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
index 24d3e17f..ea5a18e5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.png
+++ 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
index fb613827..31287cda 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history-invert.svg
@@ -1,7 +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"/>
+ <path id="clock-hands" d="M17.26 15.076s-2.385-1.935-4.005-3.062c.72-2.397 1.702-6.56 1.702-6.56s-4.35 5.364-4.877 6.7c-.463 1.168 1.46 2.21 2.346 1.678 1.9.55 4.834 1.244 4.834 1.244z"/>
+ <path id="arrow" d="M12.086 2.085C6.608 2.085 2.17 6.523 2.17 12c0 1.784.476 3.455 1.3 4.9l-2.22 2.04h5.688v-5.22L4.87 15.616c-.55-1.088-.866-2.312-.866-3.615 0-4.46 3.62-8.08 8.084-8.08 4.464 0 8.083 3.62 8.083 8.084 0 4.465-3.615 8.084-8.08 8.084-1.144 0-2.23-.247-3.212-.678l-.833 1.633c1.235.557 2.602.874 4.045.874C17.562 21.914 22 17.477 22 12c0-5.477-4.438-9.915-9.914-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
index f5a7d36e..0e177aba 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.svg
index 35f15afe..10d1b81e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/history.svg
@@ -1,7 +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="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"/>
+ <path id="clock-hands" d="M17.26 15.076s-2.385-1.935-4.005-3.062c.72-2.397 1.702-6.56 1.702-6.56s-4.35 5.364-4.877 6.7c-.463 1.168 1.46 2.21 2.346 1.678 1.9.55 4.834 1.244 4.834 1.244z"/>
+ <path id="arrow" d="M12.086 2.085C6.608 2.085 2.17 6.523 2.17 12c0 1.784.476 3.455 1.3 4.9l-2.22 2.04h5.688v-5.22L4.87 15.616c-.55-1.088-.866-2.312-.866-3.615 0-4.46 3.62-8.08 8.084-8.08 4.464 0 8.083 3.62 8.083 8.084 0 4.465-3.615 8.084-8.08 8.084-1.144 0-2.23-.247-3.212-.678l-.833 1.633c1.235.557 2.602.874 4.045.874C17.562 21.914 22 17.477 22 12c0-5.477-4.438-9.915-9.914-9.915z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr-invert.png
new file mode 100644
index 00000000..08bf391b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr-invert.svg
new file mode 100644
index 00000000..81558e02
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-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 18l-4-4-2 2-4-4-2 1-4 5h16zm2-13v15H2V5h20z"/>
+ </g>
+</svg>
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
index bebe0a9e..72ebf106 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-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>
- <path d="M20 18l-4-4-2 2-4-4-2 1-4 5h16zm2-13v15h-20v-15h20z"/>
+ <path d="M20 18l-4-4-2 2-4-4-2 1-4 5h16zm2-13v15H2V5h20z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl-invert.png
new file mode 100644
index 00000000..b5b7fb52
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl-invert.svg
new file mode 100644
index 00000000..c00d0c4a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-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="g278">
+ <path d="M4 18l4-4 2 2 4-4 2 1 4 5H4zM2 5v15h20V5H2z" id="path280"/>
+ </g>
+</svg>
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
index 88e0e3c0..ca53d9b5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/image-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="g278">
- <path d="M4 18l4-4 2 2 4-4 2 1 4 5h-16zm-2-13v15h20v-15h-20z" id="path280"/>
+ <path d="M4 18l4-4 2 2 4-4 2 1 4 5H4zM2 5v15h20V5H2z" id="path280"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr-invert.png
new file mode 100644
index 00000000..e56944a0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr-invert.svg
new file mode 100644
index 00000000..da2ddaa7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr-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>
+ <path d="M17 12V8h-4V5H0v15h20v-8h-3zM2 18l4-5 2-1 4 4 2-2 4 4H2z"/>
+ <g>
+ <path d="M24 5h-4V1h-2v4h-4v2h4v4h2V7h4z"/>
+ </g>
+</svg>
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
index 300e4b15..b775ddff 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-ltr.svg
@@ -1,7 +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"/>
+ <path d="M17 12V8h-4V5H0v15h20v-8h-3zM2 18l4-5 2-1 4 4 2-2 4 4H2z"/>
<g>
- <path d="M24 5h-4v-4h-2v4h-4v2h4v4h2v-4h4z"/>
+ <path d="M24 5h-4V1h-2v4h-4v2h4v4h2V7h4z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl-invert.png
new file mode 100644
index 00000000..eba653f7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl-invert.svg
new file mode 100644
index 00000000..7b7beaa7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl-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>
+ <path d="M7 12V8h4V5h13v15H4v-8h3zm15 6l-4-5-2-1-4 4-2-2-4 4h16z" id="path290"/>
+ <g id="g292">
+ <path d="M0 5h4V1h2v4h4v2H6v4H4V7H0z" id="path294"/>
+ </g>
+</svg>
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
index 70e32486..a7128be2 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageAdd-rtl.svg
@@ -1,7 +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"/>
+ <path d="M7 12V8h4V5h13v15H4v-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"/>
+ <path d="M0 5h4V1h2v4h4v2H6v4H4V7H0z" id="path294"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr-invert.png
new file mode 100644
index 00000000..50e7889f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr-invert.svg
new file mode 100644
index 00000000..10d770a9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-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="M19.5 4h-3V3s0-1.5 1.5-1.5c1.5.06 1.5 1.5 1.5 1.5zM21 4V3s0-3-3-3-3 3-3 3v1h-1v6h8V4zm-8 7V5H2v15h20v-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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.svg
index 8cec9f5a..b41ff435 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-ltr.svg
@@ -1,4 +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"/>
+ <path d="M19.5 4h-3V3s0-1.5 1.5-1.5c1.5.06 1.5 1.5 1.5 1.5zM21 4V3s0-3-3-3-3 3-3 3v1h-1v6h8V4zm-8 7V5H2v15h20v-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl-invert.png
new file mode 100644
index 00000000..1b1029bc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl-invert.svg
new file mode 100644
index 00000000..c821cd1f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-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="M4.5 4h3V3s0-1.5-1.5-1.5C4.5 1.56 4.5 3 4.5 3zM3 4V3s0-3 3-3 3 3 3 3v1h1v6H2V4zm8 7V5h11v15H2v-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/imageLock-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.svg
index 6bb78f71..29004d4d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/imageLock-rtl.svg
@@ -1,4 +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"/>
+ <path d="M4.5 4h3V3s0-1.5-1.5-1.5C4.5 1.56 4.5 3 4.5 3zM3 4V3s0-3 3-3 3 3 3 3v1h1v6H2V4zm8 7V5h11v15H2v-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr-invert.png
new file mode 100644
index 00000000..f1c6cd6c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr-invert.svg
new file mode 100644
index 00000000..93a43dce
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-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="M10 8h9v2h-9V8zm0 3h9v2h-9v-2zm0 3h6v2h-6v-2zm11-8H3V4h18v2zm0 14H3v-2h18v2zM3 8v8l5-4-5-4z"/>
+ </g>
+</svg>
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
index ada33959..238558a8 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-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>
- <path d="M10 8h9v2h-9v-2zm0 3h9v2h-9v-2zm0 3h6v2h-6v-2zm11-8h-18v-2h18v2zm0 14h-18v-2h18v2zm-18-12v8l5-4-5-4z"/>
+ <path d="M10 8h9v2h-9V8zm0 3h9v2h-9v-2zm0 3h6v2h-6v-2zm11-8H3V4h18v2zm0 14H3v-2h18v2zM3 8v8l5-4-5-4z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl-invert.png
new file mode 100644
index 00000000..fc486223
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl-invert.svg
new file mode 100644
index 00000000..c7c7dad2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-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="g314">
+ <path d="M14 8H5v2h9V8zm0 3H5v2h9v-2zm0 3H8v2h6v-2zM3 6h18V4H3v2zm0 14h18v-2H3v2zM21 8v8l-5-4 5-4z" id="path316"/>
+ </g>
+</svg>
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
index 9afedbbd..0334b06a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/indent-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="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"/>
+ <path d="M14 8H5v2h9V8zm0 3H5v2h9v-2zm0 3H8v2h6v-2zM3 6h18V4H3v2zm0 14h18v-2H3v2zM21 8v8l-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
index 83b00a27..a89528f8 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.png
+++ 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
index 04cd8890..a5894a1e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info-invert.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"><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"/>
+ <path id="circled-i" d="M11.5 17C8.462 17 6 14.536 6 11.5 6 8.463 8.462 6 11.5 6c3.036 0 5.5 2.462 5.5 5.5 0 3.036-2.464 5.5-5.5 5.5zm0-12C7.91 5 5 7.91 5 11.5S7.91 18 11.5 18s6.5-2.91 6.5-6.5S15.09 5 11.5 5zm.5 5v4h1v1h-3v-1h1v-3h-1v-1zm-1-2h1v1h-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
index eb0fb468..f0211899 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/info.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/info.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/info.svg
index 4bdefd46..6cff2ffa 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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">
- <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"/>
+ <path id="circled-i" d="M11.5 17C8.462 17 6 14.536 6 11.5 6 8.463 8.462 6 11.5 6c3.036 0 5.5 2.462 5.5 5.5 0 3.036-2.464 5.5-5.5 5.5zm0-12C7.91 5 5 7.91 5 11.5S7.91 18 11.5 18s6.5-2.91 6.5-6.5S15.09 5 11.5 5zm.5 5v4h1v1h-3v-1h1v-3h-1v-1zm-1-2h1v1h-1z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert-invert.png
new file mode 100644
index 00000000..dd08bc2a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert-invert.svg
new file mode 100644
index 00000000..54b8ffd7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert-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="insert">
+ <path d="M13 5h-2v6H5v2h6v6h2v-6h6v-2h-6z" id="plus"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.svg
index 0833f84f..d1e9ba33 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/insert.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="insert">
- <path d="M13 5h-2v6h-6v2h6v6h2v-6h6v-2h-6z" id="plus"/>
+ <path d="M13 5h-2v6H5v2h6v6h2v-6h6v-2h-6z" id="plus"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a-invert.png
new file mode 100644
index 00000000..7627397b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a-invert.svg
new file mode 100644
index 00000000..0fc2eb07
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a-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="italic-a">
+ <path id="a" d="M14.667 6h-1.372l-7 12H8l2.333-4h4L15 18h1.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-a.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.svg
index a0e66bff..a3a11c68 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-a.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="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"/>
+ <path id="a" d="M14.667 6h-1.372l-7 12H8l2.333-4h4L15 18h1.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem-invert.png
new file mode 100644
index 00000000..d8991424
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem-invert.svg
new file mode 100644
index 00000000..b359c47e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-keheh-jeem-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="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.3-.77.712-.87 1.125-.065.263-.036.572.062.78.19.406.54.575.844.814l.094-.12.53.624c.14.165.344.514.47.94.137.462.08.724 0 1.124h-3.44c-.34 0-.593.007-.767-.02-.34-.053-.256-.208-.234-.34.33-.127.56-.173.934-.14.29-.495.593-.886.906-1.314-.98.037-1.877.015-2.687-.094-.346-.048-.698-.187-1.094-.157-.358.026-.77.24-1.03.72-.248.447-.436.838-.658 1.28l.75-.47c.23-.14.484-.226.72-.218.156.005.274.054.405.094-.233.203-.51.4-.72.56-.3.26-.703.69-.907 1-.402.616-.693 1.085-.874 1.78-.18.69.003 1.34.468 1.75.426.378.846.52 1.28.565.65.065 1.206.093 2-.188.658-.23 1.022-.553 1.5-.97-.882.11-1.816.09-2.53.032-.87-.07-1.268-.385-1.47-.595-.27-.283-.306-.64-.155-1.22.035-.14.096-.322.25-.53.17-.228.363-.435.593-.656.45-.437 1.01-.738 1.46-.94-.044.206-.106.443-.054.688.05.23.25.38.44.47.26.12.505.153.69.154 1.42.01 2.86 0 4.28 0 .245 0 .45-.163.592-.375.14-.21.25-.48.344-.845.13-.5.094-1.062-.094-1.625-.182-.543-.418-1.01-.72-1.406-.334-.442-.673-.83-1-1.22 1.258-.813 2.717-1.237 3.97-1.686.12-.452.224-.926.313-1.313zm-9.47 8.438c-.26.394-.583.69-.874 1 .38.286.75.556 1.098.813.335-.303.626-.674.875-.97-.39-.267-.77-.587-1.093-.843z"/>
+ </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
index 7cf774fa..9f603eab 100644
--- 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
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
index d4bff1be..99980c05 100644
--- 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
@@ -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="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"/>
+ <path id="arab-keheh-jeem" d="M18.125 5.844c-1.695.555-3.297 1.162-4.594 1.938-.49.3-.77.712-.87 1.125-.065.263-.036.572.062.78.19.406.54.575.844.814l.094-.12.53.624c.14.165.344.514.47.94.137.462.08.724 0 1.124h-3.44c-.34 0-.593.007-.767-.02-.34-.053-.256-.208-.234-.34.33-.127.56-.173.934-.14.29-.495.593-.886.906-1.314-.98.037-1.877.015-2.687-.094-.346-.048-.698-.187-1.094-.157-.358.026-.77.24-1.03.72-.248.447-.436.838-.658 1.28l.75-.47c.23-.14.484-.226.72-.218.156.005.274.054.405.094-.233.203-.51.4-.72.56-.3.26-.703.69-.907 1-.402.616-.693 1.085-.874 1.78-.18.69.003 1.34.468 1.75.426.378.846.52 1.28.565.65.065 1.206.093 2-.188.658-.23 1.022-.553 1.5-.97-.882.11-1.816.09-2.53.032-.87-.07-1.268-.385-1.47-.595-.27-.283-.306-.64-.155-1.22.035-.14.096-.322.25-.53.17-.228.363-.435.593-.656.45-.437 1.01-.738 1.46-.94-.044.206-.106.443-.054.688.05.23.25.38.44.47.26.12.505.153.69.154 1.42.01 2.86 0 4.28 0 .245 0 .45-.163.592-.375.14-.21.25-.48.344-.845.13-.5.094-1.062-.094-1.625-.182-.543-.418-1.01-.72-1.406-.334-.442-.673-.83-1-1.22 1.258-.813 2.717-1.237 3.97-1.686.12-.452.224-.926.313-1.313zm-9.47 8.438c-.26.394-.583.69-.874 1 .38.286.75.556 1.098.813.335-.303.626-.674.875-.97-.39-.267-.77-.587-1.093-.843z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem-invert.png
new file mode 100644
index 00000000..960653e0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem-invert.svg
new file mode 100644
index 00000000..a0f9c0c0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-arab-meem-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="italic-arab-meem">
+ <path id="arab-meem" d="M16 9.73l-.93 2.19h-4.663c-.48 0-.857.12-1.135.366l-.06.11c-.185 2.016-.503 3.558-.956 4.627-.272.64-.633 1.252-1.082 1.833-.177.226-.22.186-.126-.12l.142-.503.17-.67.234-.87.002-.008.202-1.045.258-1.41.353-1.907c.19-.312.42-.638.695-.98.276-.342.59-.706.94-1.09.13-.092.697-.18 1.705-.266 1.05-.086 1.64-.183 1.766-.293l.065-.128c.01-.11-.01-.24-.052-.394-.044-.153-.12-.327-.232-.522-.22-.428-.438-.64-.654-.64-.293 0-.914.268-1.863.805-.36.208-.377.125-.05-.247 1.556-1.71 2.706-2.566 3.45-2.566.38 0 .67.13.86.394.135.195.25.6.344 1.21l.203 1.2c.105.586.24.895.408.925"/>
+ </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
index e8f2b620..03493be1 100644
--- 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
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
index bfbc9bf5..a9c7deff 100644
--- 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
@@ -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="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"/>
+ <path id="arab-meem" d="M16 9.73l-.93 2.19h-4.663c-.48 0-.857.12-1.135.366l-.06.11c-.185 2.016-.503 3.558-.956 4.627-.272.64-.633 1.252-1.082 1.833-.177.226-.22.186-.126-.12l.142-.503.17-.67.234-.87.002-.008.202-1.045.258-1.41.353-1.907c.19-.312.42-.638.695-.98.276-.342.59-.706.94-1.09.13-.092.697-.18 1.705-.266 1.05-.086 1.64-.183 1.766-.293l.065-.128c.01-.11-.01-.24-.052-.394-.044-.153-.12-.327-.232-.522-.22-.428-.438-.64-.654-.64-.293 0-.914.268-1.863.805-.36.208-.377.125-.05-.247 1.556-1.71 2.706-2.566 3.45-2.566.38 0 .67.13.86.394.135.195.25.6.344 1.21l.203 1.2c.105.586.24.895.408.925"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha-invert.png
new file mode 100644
index 00000000..7f6d4121
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha-invert.svg
new file mode 100644
index 00000000..fd60619c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-armn-sha-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="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.587 6h1.723c.558 0 1.042.032 1.45.095.416.063.794.173 1.136.33l4.483 2.033-.328 1.67-2.624-1.165c-.126-.058-.27-.103-.433-.134-.164-.04-.356-.06-.576-.06-.583 0-1.137.094-1.663.283-.526.19-1 .46-1.427.812-.42.35-.776.78-1.07 1.283-.294.504-.504 1.074-.63 1.71-.24 1.255-.15 2.21.27 2.87.424.65 1.19.976 2.292.976.55 0 1.045-.08 1.48-.237.437-.157.815-.378 1.136-.66.325-.29.59-.634.795-1.034.21-.4.362-.84.457-1.323l.11-.56h1.6l-.12.59c-.13.674-.356 1.288-.676 1.845-.32.55-.725 1.024-1.214 1.423-.488.395-1.053.7-1.694.923-.643.216-1.344.324-2.106.324-.767 0-1.434-.114-2-.34-.568-.226-1.025-.554-1.372-.985-.347-.436-.573-.97-.678-1.607-.105-.637-.078-1.364.08-2.184.125-.66.346-1.274.66-1.836.316-.568.697-1.067 1.144-1.497.445-.436.944-.794 1.496-1.072.55-.283 1.13-.474 1.733-.574l-.466-.23"/>
+ </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
index 4d4178ac..b5e55cca 100644
--- 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
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
index 63de0f6c..a653a27d 100644
--- 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
@@ -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="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"/>
+ <path id="armn-sha" d="M11.564 7.678c-.268-.13-.578-.22-.93-.268-.35-.047-.75-.07-1.197-.07h-1.11L8.587 6h1.723c.558 0 1.042.032 1.45.095.416.063.794.173 1.136.33l4.483 2.033-.328 1.67-2.624-1.165c-.126-.058-.27-.103-.433-.134-.164-.04-.356-.06-.576-.06-.583 0-1.137.094-1.663.283-.526.19-1 .46-1.427.812-.42.35-.776.78-1.07 1.283-.294.504-.504 1.074-.63 1.71-.24 1.255-.15 2.21.27 2.87.424.65 1.19.976 2.292.976.55 0 1.045-.08 1.48-.237.437-.157.815-.378 1.136-.66.325-.29.59-.634.795-1.034.21-.4.362-.84.457-1.323l.11-.56h1.6l-.12.59c-.13.674-.356 1.288-.676 1.845-.32.55-.725 1.024-1.214 1.423-.488.395-1.053.7-1.694.923-.643.216-1.344.324-2.106.324-.767 0-1.434-.114-2-.34-.568-.226-1.025-.554-1.372-.985-.347-.436-.573-.97-.678-1.607-.105-.637-.078-1.364.08-2.184.125-.66.346-1.274.66-1.836.316-.568.697-1.067 1.144-1.497.445-.436.944-.794 1.496-1.072.55-.283 1.13-.474 1.733-.574l-.466-.23"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c-invert.png
new file mode 100644
index 00000000..a2a2c829
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c-invert.svg
new file mode 100644
index 00000000..f2850c42
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c-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="italic-c">
+ <path id="c" d="M15.008 13.718l1.48.214c-.467 1.34-1.15 2.354-2.045 3.04-.896.686-1.9 1.03-3.015 1.03-1.36 0-2.438-.43-3.237-1.29C7.4 15.85 7 14.618 7 13.012c0-2.09.606-3.817 1.817-5.184C9.897 6.61 11.237 6 12.84 6c1.186 0 2.145.33 2.878.99.738.66 1.165 1.546 1.282 2.66l-1.397.135c-.148-.84-.453-1.464-.916-1.876-.458-.42-1.05-.63-1.78-.63-1.368 0-2.475.63-3.32 1.893-.733 1.087-1.1 2.377-1.1 3.87 0 1.194.283 2.104.848 2.732.565.628 1.3.942 2.206.942.778 0 1.477-.26 2.1-.785.63-.522 1.08-1.26 1.37-2.216"/>
+ </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
index fc6133ca..f46dea59 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.png
+++ 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
index b468deac..0a0d1103 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-c.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="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"/>
+ <path id="c" d="M15.008 13.718l1.48.214c-.467 1.34-1.15 2.354-2.045 3.04-.896.686-1.9 1.03-3.015 1.03-1.36 0-2.438-.43-3.237-1.29C7.4 15.85 7 14.618 7 13.012c0-2.09.606-3.817 1.817-5.184C9.897 6.61 11.237 6 12.84 6c1.186 0 2.145.33 2.878.99.738.66 1.165 1.546 1.282 2.66l-1.397.135c-.148-.84-.453-1.464-.916-1.876-.458-.42-1.05-.63-1.78-.63-1.368 0-2.475.63-3.32 1.893-.733 1.087-1.1 2.377-1.1 3.87 0 1.194.283 2.104.848 2.732.565.628 1.3.942 2.206.942.778 0 1.477-.26 2.1-.785.63-.522 1.08-1.26 1.37-2.216"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d-invert.png
new file mode 100644
index 00000000..33a41cb7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d-invert.svg
new file mode 100644
index 00000000..8ca4218a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d-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="italic-d">
+ <path id="d" d="M7 18L9.462 6h3.557c.85 0 1.5.063 1.95.188.645.17 1.195.472 1.65.91.457.43.8.97 1.03 1.62.23.65.347 1.378.347 2.186 0 .966-.146 1.847-.436 2.644-.283.79-.66 1.49-1.126 2.095-.46.6-.947 1.072-1.456 1.416-.504.334-1.1.585-1.794.75-.526.125-1.172.19-1.94.19H7m1.86-1.36h1.866c.842 0 1.59-.08 2.245-.24.41-.097.76-.242 1.05-.433.38-.247.727-.57 1.038-.975.408-.535.732-1.143.974-1.825.247-.687.37-1.467.37-2.34 0-.97-.166-1.716-.5-2.235-.332-.524-.755-.87-1.27-1.04-.38-.126-.974-.188-1.78-.188H11L9.095 16.64"/>
+ </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
index 1711ef95..4ace3f35 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.png
+++ 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
index 92a834d9..feadca08 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-d.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="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"/>
+ <path id="d" d="M7 18L9.462 6h3.557c.85 0 1.5.063 1.95.188.645.17 1.195.472 1.65.91.457.43.8.97 1.03 1.62.23.65.347 1.378.347 2.186 0 .966-.146 1.847-.436 2.644-.283.79-.66 1.49-1.126 2.095-.46.6-.947 1.072-1.456 1.416-.504.334-1.1.585-1.794.75-.526.125-1.172.19-1.94.19H7m1.86-1.36h1.866c.842 0 1.59-.08 2.245-.24.41-.097.76-.242 1.05-.433.38-.247.727-.57 1.038-.975.408-.535.732-1.143.974-1.825.247-.687.37-1.467.37-2.34 0-.97-.166-1.716-.5-2.235-.332-.524-.755-.87-1.27-1.04-.38-.126-.974-.188-1.78-.188H11L9.095 16.64"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e-invert.png
new file mode 100644
index 00000000..cf39073d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e-invert.svg
new file mode 100644
index 00000000..f6c18e55
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e-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="italic-e">
+ <path id="e" d="M7 18L9.474 6H18l-.282 1.367H10.77L10.02 11h6.09l-.28 1.367H9.74l-.88 4.273h7.44L16.018 18H7"/>
+ </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
index f5b44d9e..882a5354 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.png
+++ 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
index 66a5ef5d..f3851498 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-e.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="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"/>
+ <path id="e" d="M7 18L9.474 6H18l-.282 1.367H10.77L10.02 11h6.09l-.28 1.367H9.74l-.88 4.273h7.44L16.018 18H7"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan-invert.png
new file mode 100644
index 00000000..68e90a92
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan-invert.svg
new file mode 100644
index 00000000..86699616
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-geor-kan-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="italic-geor-kan">
+ <path id="geor-kan" d="M15.057 14.663C14.617 16.888 13.223 18 10.88 18 8.96 18 8 17.213 8 15.64c0-.298.036-.624.108-.977.083-.43.245-.836.488-1.217l1.24.605-.206.617c-.055.26-.083.497-.083.712 0 .97.52 1.457 1.564 1.457 1.31 0 2.105-.723 2.387-2.17l.058-.33c.044-.222.066-.426.066-.614 0-.927-.546-1.39-1.64-1.39h-1.115l.248-1.26h1.118c1.203-.004 1.91-.55 2.12-1.64.04-.18.057-.355.057-.52 0-1.144-.9-1.715-2.697-1.715L11.94 6C14.646 6 16 6.877 16 8.627c0 .248-.027.516-.082.803-.204 1.092-1.05 1.824-2.54 2.194l-.033.166c1.23.2 1.845.823 1.845 1.872 0 .21-.025.433-.074.67l-.058.332"/>
+ </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
index e728cd7b..7f9da2ac 100644
--- 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
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
index 3398904d..65670ef4 100644
--- 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
@@ -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="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"/>
+ <path id="geor-kan" d="M15.057 14.663C14.617 16.888 13.223 18 10.88 18 8.96 18 8 17.213 8 15.64c0-.298.036-.624.108-.977.083-.43.245-.836.488-1.217l1.24.605-.206.617c-.055.26-.083.497-.083.712 0 .97.52 1.457 1.564 1.457 1.31 0 2.105-.723 2.387-2.17l.058-.33c.044-.222.066-.426.066-.614 0-.927-.546-1.39-1.64-1.39h-1.115l.248-1.26h1.118c1.203-.004 1.91-.55 2.12-1.64.04-.18.057-.355.057-.52 0-1.144-.9-1.715-2.697-1.715L11.94 6C14.646 6 16 6.877 16 8.627c0 .248-.027.516-.082.803-.204 1.092-1.05 1.824-2.54 2.194l-.033.166c1.23.2 1.845.823 1.845 1.872 0 .21-.025.433-.074.67l-.058.332"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i-invert.png
new file mode 100644
index 00000000..ad101c78
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i-invert.svg
new file mode 100644
index 00000000..ecde4b76
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i-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="italic-i">
+ <path id="i" d="M12.5 18l.25-.995h-1.5l2.508-10.037h1.5L15.5 6h-5l-.242.968h1.5l-2.51 10.037h-1.5L7.5 18z"/>
+ </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
index 3c6b3c1b..28aab448 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.png
+++ 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
index 93bec5a6..e670e9bf 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-i.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="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"/>
+ <path id="i" d="M12.5 18l.25-.995h-1.5l2.508-10.037h1.5L15.5 6h-5l-.242.968h1.5l-2.51 10.037h-1.5L7.5 18z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k-invert.png
new file mode 100644
index 00000000..260a03c2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k-invert.svg
new file mode 100644
index 00000000..730fb8ac
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k-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="italic-k">
+ <path id="k" d="M12.018 10.652L17 6h-2l-5.31 5.234L11 6H9.5l-3 12H8l1.173-4.693 1.54-1.438C11 16 14 18 14 18h2s-4-2-3.982-7.348z"/>
+ </g>
+</svg>
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
index d4831549..38bcd73a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-k.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="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"/>
+ <path id="k" d="M12.018 10.652L17 6h-2l-5.31 5.234L11 6H9.5l-3 12H8l1.173-4.693 1.54-1.438C11 16 14 18 14 18h2s-4-2-3.982-7.348z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s-invert.png
new file mode 100644
index 00000000..954bfbf7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s-invert.svg
new file mode 100644
index 00000000..9515299a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s-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="italic-s">
+ <path id="s" d="M16.474 6.59l-.302 1.525c-.522-.28-1.04-.488-1.557-.628-.51-.145-1.007-.217-1.487-.217-.935 0-1.68.204-2.23.612-.554.408-.83.95-.83 1.627 0 .37.1.654.302.86.207.192.733.404 1.58.63l.937.233c1.06.274 1.795.622 2.208 1.046.413.42.62 1.007.62 1.766 0 1.167-.46 2.117-1.38 2.85-.913.734-2.12 1.1-3.617 1.1-.615 0-1.232-.06-1.852-.185-.62-.12-1.242-.3-1.867-.55l.314-1.61c.573.356 1.147.625 1.72.806.578.18 1.154.27 1.728.27.976 0 1.76-.216 2.347-.65.59-.434.883-1 .883-1.697 0-.465-.12-.816-.356-1.054-.233-.243-.737-.462-1.512-.658l-.937-.24c-1.07-.28-1.8-.6-2.19-.964-.39-.367-.584-.878-.584-1.534 0-1.152.442-2.094 1.325-2.828.89-.74 2.043-1.108 3.463-1.108.553 0 1.1.05 1.642.147.542.1 1.085.246 1.627.443"/>
+ </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
index 4fc10c50..4a7b1fc2 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.png
+++ 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
index 4f6364cb..615e5f22 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/italic-s.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="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"/>
+ <path id="s" d="M16.474 6.59l-.302 1.525c-.522-.28-1.04-.488-1.557-.628-.51-.145-1.007-.217-1.487-.217-.935 0-1.68.204-2.23.612-.554.408-.83.95-.83 1.627 0 .37.1.654.302.86.207.192.733.404 1.58.63l.937.233c1.06.274 1.795.622 2.208 1.046.413.42.62 1.007.62 1.766 0 1.167-.46 2.117-1.38 2.85-.913.734-2.12 1.1-3.617 1.1-.615 0-1.232-.06-1.852-.185-.62-.12-1.242-.3-1.867-.55l.314-1.61c.573.356 1.147.625 1.72.806.578.18 1.154.27 1.728.27.976 0 1.76-.216 2.347-.65.59-.434.883-1 .883-1.697 0-.465-.12-.816-.356-1.054-.233-.243-.737-.462-1.512-.658l-.937-.24c-1.07-.28-1.8-.6-2.19-.964-.39-.367-.584-.878-.584-1.534 0-1.152.442-2.094 1.325-2.828.89-.74 2.043-1.108 3.463-1.108.553 0 1.1.05 1.642.147.542.1 1.085.246 1.627.443"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr-invert.png
new file mode 100644
index 00000000..4f5e01ea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr-invert.svg
new file mode 100644
index 00000000..cbcfff04
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-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="M16 9V8h-6v1h6zm-2 2v-1h-4v1h4zM6 5h1v16H6V5zm2 0h10v13c0 1.7-1.3 3-3 3H8V5z"/>
+</svg>
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
index c7e16033..c9fa5536 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-ltr.svg
@@ -1,4 +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"/>
+ <path d="M16 9V8h-6v1h6zm-2 2v-1h-4v1h4zM6 5h1v16H6V5zm2 0h10v13c0 1.7-1.3 3-3 3H8V5z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl-invert.png
new file mode 100644
index 00000000..519bf10d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl-invert.svg
new file mode 100644
index 00000000..6b0afc05
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-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="M8 9V8h6v1H8zm2 2v-1h4v1h-4zm8-6h-1v16h1V5zm-2 0H6v13c0 1.7 1.3 3 3 3h7V5z" id="path326"/>
+</svg>
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
index 2d16be37..393f19d4 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/journal-rtl.svg
@@ -1,4 +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"/>
+ <path d="M8 9V8h6v1H8zm2 2v-1h4v1h-4zm8-6h-1v16h1V5zm-2 0H6v13c0 1.7 1.3 3 3 3h7V5z" id="path326"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr-invert.png
new file mode 100644
index 00000000..1e9d92dd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr-invert.svg
new file mode 100644
index 00000000..131bbdbc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-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.5 4C11.5 4 9 6.5 9 9.5c0 1 .3 1.9.7 2.8L4 18v2h4v-2h2v-2h2l1.2-1.2c.4.1.9.2 1.3.2 3 0 5.5-2.5 5.5-5.5S17.5 4 14.5 4zM16 9c-.8 0-1.5-.7-1.5-1.5S15.2 6 16 6s1.5.7 1.5 1.5S16.8 9 16 9z"/>
+</svg>
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
index 8dfb89ae..fc0d3c34 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-ltr.svg
@@ -1,4 +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"/>
+ <path d="M14.5 4C11.5 4 9 6.5 9 9.5c0 1 .3 1.9.7 2.8L4 18v2h4v-2h2v-2h2l1.2-1.2c.4.1.9.2 1.3.2 3 0 5.5-2.5 5.5-5.5S17.5 4 14.5 4zM16 9c-.8 0-1.5-.7-1.5-1.5S15.2 6 16 6s1.5.7 1.5 1.5S16.8 9 16 9z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl-invert.png
new file mode 100644
index 00000000..9d46092b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl-invert.svg
new file mode 100644
index 00000000..fbd3329d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-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="M9.5 4c3 0 5.5 2.5 5.5 5.5 0 1-.3 1.9-.7 2.8L20 18v2h-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.5S6.5 4 9.5 4zM8 9c.8 0 1.5-.7 1.5-1.5S8.8 6 8 6s-1.5.7-1.5 1.5S7.2 9 8 9z" id="path336"/>
+</svg>
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
index 06392874..8975b667 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/key-rtl.svg
@@ -1,4 +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"/>
+ <path d="M9.5 4c3 0 5.5 2.5 5.5 5.5 0 1-.3 1.9-.7 2.8L20 18v2h-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.5S6.5 4 9.5 4zM8 9c.8 0 1.5-.7 1.5-1.5S8.8 6 8 6s-1.5.7-1.5 1.5S7.2 9 8 9z" id="path336"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr-invert.png
new file mode 100644
index 00000000..1dcd4c30
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr-invert.svg
new file mode 100644
index 00000000..84479e8b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-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="M3 7v9c0 1.7 1.3 3 3 3h15V7H3zm8 2h2v2h-2V9zm0 3h2v2h-2v-2zM8 9h2v2H8V9zm0 3h2v2H8v-2zm-1 5H6c-.6 0-1-.4-1-1v-1h2v2zm0-3H5v-2h2v2zm0-3H5V9h2v2zm9 6H8v-2h8v2zm0-3h-2v-2h2v2zm0-3h-2V9h2v2zm3 6h-2v-2h2v2zm0-3h-2v-2h2v2zm0-3h-2V9h2v2z"/>
+ </g>
+</svg>
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
index ea5055c8..2bb795ec 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-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>
- <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"/>
+ <path d="M3 7v9c0 1.7 1.3 3 3 3h15V7H3zm8 2h2v2h-2V9zm0 3h2v2h-2v-2zM8 9h2v2H8V9zm0 3h2v2H8v-2zm-1 5H6c-.6 0-1-.4-1-1v-1h2v2zm0-3H5v-2h2v2zm0-3H5V9h2v2zm9 6H8v-2h8v2zm0-3h-2v-2h2v2zm0-3h-2V9h2v2zm3 6h-2v-2h2v2zm0-3h-2v-2h2v2zm0-3h-2V9h2v2z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl-invert.png
new file mode 100644
index 00000000..61c95be1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl-invert.svg
new file mode 100644
index 00000000..27007292
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-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="g346">
+ <path d="M21 7v9c0 1.7-1.3 3-3 3H3V7h18zm-8 2h-2v2h2V9zm0 3h-2v2h2v-2zm3-3h-2v2h2V9zm0 3h-2v2h2v-2zm1 5h1c.6 0 1-.4 1-1v-1h-2v2zm0-3h2v-2h-2v2zm0-3h2V9h-2v2zm-9 6h8v-2H8v2zm0-3h2v-2H8v2zm0-3h2V9H8v2zm-3 6h2v-2H5v2zm0-3h2v-2H5v2zm0-3h2V9H5v2z" id="path348"/>
+ </g>
+</svg>
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
index b35d108d..b7b47cc3 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/keyboard-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="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"/>
+ <path d="M21 7v9c0 1.7-1.3 3-3 3H3V7h18zm-8 2h-2v2h2V9zm0 3h-2v2h2v-2zm3-3h-2v2h2V9zm0 3h-2v2h2v-2zm1 5h1c.6 0 1-.4 1-1v-1h-2v2zm0-3h2v-2h-2v2zm0-3h2V9h-2v2zm-9 6h8v-2H8v2zm0-3h2v-2H8v2zm0-3h2V9H8v2zm-3 6h2v-2H5v2zm0-3h2v-2H5v2zm0-3h2V9H5v2z" id="path348"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/language-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/language-invert.png
new file mode 100644
index 00000000..ad816df8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/language-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/language-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/language-invert.svg
new file mode 100644
index 00000000..abc618e8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/language-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="language">
+ <path id="japanese" d="M17.533 9.81l.27-.59 1.042.407-.18.363c.66.27 1.1.468 1.312.59.33.21.618.513.86.904.21.393.316.846.316 1.358 0 .786-.302 1.48-.905 2.083-.604.634-1.66 1.057-3.17 1.268-.12-.36-.257-.68-.407-.95.97-.15 1.65-.333 2.04-.545.455-.21.786-.48 1-.813.21-.303.313-.663.313-1.087 0-.482-.135-.905-.406-1.27-.33-.33-.8-.588-1.402-.77-.332.635-.648 1.118-.95 1.45-.242.332-.694.906-1.358 1.72.09.394.18.71.272.952l-1.043.362-.09-.498c-.424.36-.802.617-1.134.77-.36.15-.664.226-.905.226-.303 0-.574-.136-.814-.407-.243-.3-.362-.68-.362-1.132 0-.6.137-1.143.408-1.63.24-.45.603-.89 1.086-1.31.273-.24.726-.53 1.36-.86 0-.27.03-.8.09-1.584-.514.03-.92.045-1.222.045-.393 0-.71-.015-.95-.045l-.047-1.04c.726.09 1.495.134 2.31.134 0-.15.076-.74.228-1.767l1.177.184c-.15.542-.256 1.04-.316 1.493.24-.03.542-.077.905-.138.36-.06.573-.09.634-.09s.647-.15 1.765-.453l.045 1.04c-.966.242-2.144.44-3.53.59-.063.662-.093 1.085-.093 1.265.664-.15 1.285-.225 1.858-.225zm-2.672 3.893c-.06-.48-.132-1.252-.223-2.31-.573.424-1.04.86-1.403 1.313-.302.423-.45.875-.45 1.358 0 .24.043.438.135.588.09.092.194.137.315.137.364 0 .908-.365 1.63-1.09zm.775-2.763c0 .483.03 1.088.09 1.81.604-.904 1.057-1.598 1.36-2.08-.575.06-1.06.15-1.45.27z"/>
+ <path id="english" d="M9.497 15.98h1.85L8.265 7.033h-1.85l-3.08 8.95h1.85L5.74 14h3.21l.547 1.98zm-3.49-3.376L7.34 8.822l1.343 3.782H6.008z"/>
+ </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
index c864384e..b4f0875e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/language.png
+++ 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
index 081e49a1..956aba1f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/language.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/language.svg
@@ -1,7 +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"/>
+ <path id="japanese" d="M17.533 9.81l.27-.59 1.042.407-.18.363c.66.27 1.1.468 1.312.59.33.21.618.513.86.904.21.393.316.846.316 1.358 0 .786-.302 1.48-.905 2.083-.604.634-1.66 1.057-3.17 1.268-.12-.36-.257-.68-.407-.95.97-.15 1.65-.333 2.04-.545.455-.21.786-.48 1-.813.21-.303.313-.663.313-1.087 0-.482-.135-.905-.406-1.27-.33-.33-.8-.588-1.402-.77-.332.635-.648 1.118-.95 1.45-.242.332-.694.906-1.358 1.72.09.394.18.71.272.952l-1.043.362-.09-.498c-.424.36-.802.617-1.134.77-.36.15-.664.226-.905.226-.303 0-.574-.136-.814-.407-.243-.3-.362-.68-.362-1.132 0-.6.137-1.143.408-1.63.24-.45.603-.89 1.086-1.31.273-.24.726-.53 1.36-.86 0-.27.03-.8.09-1.584-.514.03-.92.045-1.222.045-.393 0-.71-.015-.95-.045l-.047-1.04c.726.09 1.495.134 2.31.134 0-.15.076-.74.228-1.767l1.177.184c-.15.542-.256 1.04-.316 1.493.24-.03.542-.077.905-.138.36-.06.573-.09.634-.09s.647-.15 1.765-.453l.045 1.04c-.966.242-2.144.44-3.53.59-.063.662-.093 1.085-.093 1.265.664-.15 1.285-.225 1.858-.225zm-2.672 3.893c-.06-.48-.132-1.252-.223-2.31-.573.424-1.04.86-1.403 1.313-.302.423-.45.875-.45 1.358 0 .24.043.438.135.588.09.092.194.137.315.137.364 0 .908-.365 1.63-1.09zm.775-2.763c0 .483.03 1.088.09 1.81.604-.904 1.057-1.598 1.36-2.08-.575.06-1.06.15-1.45.27z"/>
+ <path id="english" d="M9.497 15.98h1.85L8.265 7.033h-1.85l-3.08 8.95h1.85L5.74 14h3.21l.547 1.98zm-3.49-3.376L7.34 8.822l1.343 3.782H6.008z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-ltr.png
new file mode 100644
index 00000000..79a28248
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-ltr.svg
new file mode 100644
index 00000000..166ce476
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M20.8 20h-8.1v-.8c.4 0 .8-.1 1.3-.2s.8-.2.8-.4v-.2c0-.1 0-.2-.1-.3L13.4 15H8.3c-.1.3-.2.6-.4 1-.1.4-.3.7-.4 1-.1.4-.2.7-.2.8v.4c0 .2.2.4.5.6.3.2.9.3 1.7.3v.9H3.4v-.8c.2 0 .5-.1.8-.1.3-.1.5-.1.7-.2.3-.2.5-.4.7-.6.2-.3.4-.6.5-.9.8-2 1.6-3.9 2.4-5.9.8-2 1.7-4.1 2.7-6.5h2.1c1.4 3.3 2.4 6 3.2 7.9.8 1.9 1.4 3.6 2 4.8l.3.6c.1.2.3.3.6.5.2.1.4.2.7.3.3.1.5.1.7.1v.8zM13 14l-2.1-5.3L8.8 14H13z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-rtl.png
new file mode 100644
index 00000000..79a28248
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-rtl.svg
new file mode 100644
index 00000000..166ce476
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/largerText-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M20.8 20h-8.1v-.8c.4 0 .8-.1 1.3-.2s.8-.2.8-.4v-.2c0-.1 0-.2-.1-.3L13.4 15H8.3c-.1.3-.2.6-.4 1-.1.4-.3.7-.4 1-.1.4-.2.7-.2.8v.4c0 .2.2.4.5.6.3.2.9.3 1.7.3v.9H3.4v-.8c.2 0 .5-.1.8-.1.3-.1.5-.1.7-.2.3-.2.5-.4.7-.6.2-.3.4-.6.5-.9.8-2 1.6-3.9 2.4-5.9.8-2 1.7-4.1 2.7-6.5h2.1c1.4 3.3 2.4 6 3.2 7.9.8 1.9 1.4 3.6 2 4.8l.3.6c.1.2.3.3.6.5.2.1.4.2.7.3.3.1.5.1.7.1v.8zM13 14l-2.1-5.3L8.8 14H13z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr-invert.png
new file mode 100644
index 00000000..edee6ac7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr-invert.svg
new file mode 100644
index 00000000..a848318e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr-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="layout-ltr">
+ <path id="text" d="M5 19V5h6v8h8v6H5z"/>
+ <path id="float" d="M13 5v6h6V5h-6zm5 5h-4V6h4v4z"/>
+ </g>
+</svg>
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
index 47e71b39..c3be66cc 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-ltr.svg
@@ -1,7 +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"/>
+ <path id="text" d="M5 19V5h6v8h8v6H5z"/>
+ <path id="float" d="M13 5v6h6V5h-6zm5 5h-4V6h4v4z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl-invert.png
new file mode 100644
index 00000000..83e0145a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl-invert.svg
new file mode 100644
index 00000000..b8c4586b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl-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="layout-rtl">
+ <path id="text" d="M5 19v-6h8V5h6v14H5z"/>
+ <path id="float" d="M5 5v6h6V5H5zm1 1h4v4H6V6z"/>
+ </g>
+</svg>
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
index fe9ee617..ce7feb8d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/layout-rtl.svg
@@ -1,7 +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"/>
+ <path id="text" d="M5 19v-6h8V5h6v14H5z"/>
+ <path id="float" d="M5 5v6h6V5H5zm1 1h4v4H6V6z"/>
</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
index 1b1e2ed3..ca5beaf3 100644
--- 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
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
index c98df5cf..9cf9d286 100644
--- 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
@@ -1,13 +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>
-<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>
+<?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="g3097">
+ <path d="M15.387 4.33c-2.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.6l-2.6 2.6c-.4.4-1.2.7-1.8.7-1.4 0-2.1-.9-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.6c.9-.9 1.5-2 1.5-3.3-.2-2.2-2.2-4.1-4.4-4.1zm-4.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.6l2.6-2.6c.4-.4 1.2-.7 1.8-.7 1.4 0 2.1 1 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-1.7 1.7-1.7 4.4 0 6 1.6 1.6 4.4 1.7 5.9 0l1.9-1.9c-.3.1-.6.1-.9.1-.5 0-.9 0-1.3-.2z" id="path3099"/>
+ </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
index 1fe66f1e..25980e60 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.png
+++ 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
index 841ba7d4..dd3df73a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/link-ltr.svg
@@ -1,13 +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">
-<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>
+<?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="g3097">
+ <path d="M15.387 4.33c-2.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.6l-2.6 2.6c-.4.4-1.2.7-1.8.7-1.4 0-2.1-.9-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.6c.9-.9 1.5-2 1.5-3.3-.2-2.2-2.2-4.1-4.4-4.1zm-4.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.6l2.6-2.6c.4-.4 1.2-.7 1.8-.7 1.4 0 2.1 1 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-1.7 1.7-1.7 4.4 0 6 1.6 1.6 4.4 1.7 5.9 0l1.9-1.9c-.3.1-.6.1-.9.1-.5 0-.9 0-1.3-.2z" id="path3099"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr-invert.png
new file mode 100644
index 00000000..f304cef0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr-invert.svg
new file mode 100644
index 00000000..686a8e7c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-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="M21 7H9V5h12v2zM7 6c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm14 7H9v-2h12v2zM7 12c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm14 7H9v-2h12v2zM7 18c0 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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.svg
index 09a4ff5d..5f0b15f8 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-ltr.svg
@@ -1,4 +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"/>
+ <path d="M21 7H9V5h12v2zM7 6c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm14 7H9v-2h12v2zM7 12c0 1.1-.9 2-2 2s-2-.9-2-2 .9-2 2-2 2 .9 2 2zm14 7H9v-2h12v2zM7 18c0 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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl-invert.png
new file mode 100644
index 00000000..41cdbfbb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl-invert.svg
new file mode 100644
index 00000000..be5bd9f9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-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="M3 7h12V5H3v2zm14-1c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2zM3 13h12v-2H3v2zm14-1c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2zM3 19h12v-2H3v2zm14-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/listBullet-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.svg
index 67b9dfee..f29a05e4 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listBullet-rtl.svg
@@ -1,4 +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"/>
+ <path d="M3 7h12V5H3v2zm14-1c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2zM3 13h12v-2H3v2zm14-1c0 1.1.9 2 2 2s2-.9 2-2-.9-2-2-2-2 .9-2 2zM3 19h12v-2H3v2zm14-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr-invert.png
new file mode 100644
index 00000000..d1caa843
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr-invert.svg
new file mode 100644
index 00000000..58ffe88e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-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="M21 7H8V5h13v2zm0 6H8v-2h13v2zm0 6H8v-2h13v2zM4 4h2v4H5V5H4zm-1 6V9h3v3H4v1h2v1H3v-3h2v-1zm3 10H3v-1h2v-1H4v-1h1v-1H3v-1h3z"/>
+</svg>
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
index 87e8854e..8e849a76 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-ltr.svg
@@ -1,4 +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"/>
+ <path d="M21 7H8V5h13v2zm0 6H8v-2h13v2zm0 6H8v-2h13v2zM4 4h2v4H5V5H4zm-1 6V9h3v3H4v1h2v1H3v-3h2v-1zm3 10H3v-1h2v-1H4v-1h1v-1H3v-1h3z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl-invert.png
new file mode 100644
index 00000000..ded07659
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl-invert.svg
new file mode 100644
index 00000000..d319205a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-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="M3 7h13V5H3zm0 6h13v-2H3zm0 6h13v-2H3zM18 4h2v4h-1V5h-1zm0 6V9h3v3h-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/listNumbered-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.svg
index 831a5fb9..331dc8d2 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/listNumbered-rtl.svg
@@ -1,4 +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"/>
+ <path d="M3 7h13V5H3zm0 6h13v-2H3zm0 6h13v-2H3zM18 4h2v4h-1V5h-1zm0 6V9h3v3h-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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr-destructive.svg
index 934cb4e5..6e17f592 100644
--- 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
@@ -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"><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"/>
+ <path d="M15 8s0-3-2.5-3S10 8 10 8v1h5zm2 0v1h2v10H9c-1.7 0-3-1.3-3-3V9h2V8s0-5 4.5-5S17 8 17 8z" id="path392"/>
</g>
</svg>
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
index 7aed0f67..fd9359ae 100644
--- 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
@@ -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"><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"/>
+ <path d="M15 8s0-3-2.5-3S10 8 10 8v1h5zm2 0v1h2v10H9c-1.7 0-3-1.3-3-3V9h2V8s0-5 4.5-5S17 8 17 8z" id="path392"/>
</g>
</svg>
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
index 59454922..80d3acef 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-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="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"/>
+ <path d="M15 8s0-3-2.5-3S10 8 10 8v1h5zm2 0v1h2v10H9c-1.7 0-3-1.3-3-3V9h2V8s0-5 4.5-5S17 8 17 8z" id="path392"/>
</g>
</svg>
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
index 64c23244..9e88270b 100644
--- 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
@@ -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"><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"/>
+ <path d="M10 8s0-3 2.5-3S15 8 15 8v1h-5zM8 8v1H6v10h10c1.7 0 3-1.3 3-3V9h-2V8s0-5-4.5-5S8 8 8 8z" id="path392"/>
</g>
</svg>
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
index 63cb2ebb..bcb3f4fa 100644
--- 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
@@ -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"><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"/>
+ <path d="M10 8s0-3 2.5-3S15 8 15 8v1h-5zM8 8v1H6v10h10c1.7 0 3-1.3 3-3V9h-2V8s0-5-4.5-5S8 8 8 8z" id="path392"/>
</g>
</svg>
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
index 0591f661..21881e98 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/lock-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="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"/>
+ <path d="M10 8s0-3 2.5-3S15 8 15 8v1h-5zM8 8v1H6v10h10c1.7 0 3-1.3 3-3V9h-2V8s0-5-4.5-5S8 8 8 8z" id="path392"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr-invert.png
new file mode 100644
index 00000000..52467f2e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr-invert.svg
new file mode 100644
index 00000000..dcbf49e9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-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="M15 14v3l5-4.5L15 8v3H8c0 1.7 1.3 3 3 3h4zm-1-9H4v15h10v-2H6V7h8V5z"/>
+ </g>
+</svg>
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
index 4af765ca..61c369fe 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-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>
- <path d="M15 14v3l5-4.5-5-4.5v3h-7c0 1.7 1.3 3 3 3h4zm-1-9h-10v15h10v-2h-8v-11h8v-2z"/>
+ <path d="M15 14v3l5-4.5L15 8v3H8c0 1.7 1.3 3 3 3h4zm-1-9H4v15h10v-2H6V7h8V5z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl-invert.png
new file mode 100644
index 00000000..734b5f28
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl-invert.svg
new file mode 100644
index 00000000..e953bab3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-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="g402">
+ <path d="M9 14v3l-5-4.5L9 8v3h7c0 1.7-1.3 3-3 3H9zm1-9h10v15H10v-2h8V7h-8V5z" id="path404"/>
+ </g>
+</svg>
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
index f72c04ad..5cb4687b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logOut-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="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"/>
+ <path d="M9 14v3l-5-4.5L9 8v3h7c0 1.7-1.3 3-3 3H9zm1-9h10v15H10v-2h8V7h-8V5z" id="path404"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc-invert.png
new file mode 100644
index 00000000..7dcc6fa2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc-invert.svg
new file mode 100644
index 00000000..a59d4428
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-cc-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="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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons-invert.png
new file mode 100644
index 00000000..7be13906
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons-invert.svg
new file mode 100644
index 00000000..40a9ab6e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons-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>
+ <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-1V14l-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-1L7 14v.8H6c.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.4C5 10.6 4 12.7 4 15c0 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-wikimediaCommons.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.svg
index 079e1773..c195d4ca 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikimediaCommons.svg
@@ -1,7 +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"/>
+ <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-1V14l-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-1L7 14v.8H6c.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.4C5 10.6 4 12.7 4 15c0 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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia-invert.png
new file mode 100644
index 00000000..ea3aec32
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia-invert.svg
new file mode 100644
index 00000000..a21fb464
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia-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="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-.4L12.2 13l-2.8 5.5c-.1.3-.3.4-.5.4s-.4-.1-.5-.4L4.1 8.4c-.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.4L10 8.4c-.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/logo-wikipedia.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.png
index 8629f29e..05bf48c4 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.png
+++ 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
index 6672d9dc..587780cf 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/logo-wikipedia.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>
- <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"/>
+ <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-.4L12.2 13l-2.8 5.5c-.1.3-.3.4-.5.4s-.4-.1-.5-.4L4.1 8.4c-.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.4L10 8.4c-.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr-invert.png
new file mode 100644
index 00000000..054cfd2e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr-invert.svg
new file mode 100644
index 00000000..b9881877
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-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="M15 6L9 4 3 6v15l6-2 6 2 6-2V4l-6 2zM8.7 18.1L4 19.6V6.7L9 5v12.9l-.3.2zm11.3.2L15 20V7.1l.3-.1L20 5.4v12.9z"/>
+</svg>
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
index 0fc47737..0e5a52e4 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-ltr.svg
@@ -1,4 +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"/>
+ <path d="M15 6L9 4 3 6v15l6-2 6 2 6-2V4l-6 2zM8.7 18.1L4 19.6V6.7L9 5v12.9l-.3.2zm11.3.2L15 20V7.1l.3-.1L20 5.4v12.9z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl-invert.png
new file mode 100644
index 00000000..afd1dc78
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl-invert.svg
new file mode 100644
index 00000000..442891ab
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-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="M9 6l6-2 6 2v15l-6-2-6 2-6-2V4l6 2zm6.3 12.1l4.7 1.5V6.7L15 5v12.9l.3.2zM4 18.3L9 20V7.1L8.7 7 4 5.4v12.9z" id="path424"/>
+</svg>
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
index b33f1e39..36a5b24e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/map-rtl.svg
@@ -1,4 +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"/>
+ <path d="M9 6l6-2 6 2v15l-6-2-6 2-6-2V4l6 2zm6.3 12.1l4.7 1.5V6.7L15 5v12.9l.3.2zM4 18.3L9 20V7.1L8.7 7 4 5.4v12.9z" id="path424"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin-invert.png
new file mode 100644
index 00000000..3b041ddd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin-invert.svg
new file mode 100644
index 00000000..42d8e7c8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin-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="M19 12c0-3.9-3.1-7-7-7s-7 3.1-7 7c0 1.4.4 2.6 1.1 3.7L12 23l5.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/mapPin.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.svg
index f422c84f..5310f828 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPin.svg
@@ -1,4 +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"/>
+ <path d="M19 12c0-3.9-3.1-7-7-7s-7 3.1-7 7c0 1.4.4 2.6 1.1 3.7L12 23l5.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr-invert.png
new file mode 100644
index 00000000..ab176c94
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr-invert.svg
new file mode 100644
index 00000000..ded3fd14
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-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="g434">
+ <g id="g436">
+ <path d="M24 4h-4V0h-2v4h-4v2h4v4h2V6h4z" id="path438"/>
+ </g>
+ </g>
+ <path d="M18 11h-1V7.1l-.1-.1H13V5.1c-.3-.1-.7-.1-1-.1-3.9 0-7 3.1-7 7 0 1.4.4 2.6 1.1 3.7L12 23l5.9-7.3c.7-1.1 1.1-2.3 1.1-3.7 0-.3 0-.7-.1-1H18zm-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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.svg
index 9a54eb6a..a1b024e5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-ltr.svg
@@ -2,8 +2,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"/>
+ <path d="M24 4h-4V0h-2v4h-4v2h4v4h2V6h4z" 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"/>
+ <path d="M18 11h-1V7.1l-.1-.1H13V5.1c-.3-.1-.7-.1-1-.1-3.9 0-7 3.1-7 7 0 1.4.4 2.6 1.1 3.7L12 23l5.9-7.3c.7-1.1 1.1-2.3 1.1-3.7 0-.3 0-.7-.1-1H18zm-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl-invert.png
new file mode 100644
index 00000000..9cb03433
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl-invert.svg
new file mode 100644
index 00000000..537d914e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-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="g434">
+ <g id="g436">
+ <path d="M0 4h4V0h2v4h4v2H6v4H4V6H0z" id="path438"/>
+ </g>
+ </g>
+ <path d="M6 11h1V7.1l.1-.1H11V5.1c.3-.1.7-.1 1-.1 3.9 0 7 3.1 7 7 0 1.4-.4 2.6-1.1 3.7L12 23l-5.9-7.3C5.4 14.6 5 13.4 5 12c0-.3 0-.7.1-1H6zm6 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/mapPinAdd-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.svg
index d3e152e0..eb92036c 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/mapPinAdd-rtl.svg
@@ -2,8 +2,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"/>
+ <path d="M0 4h4V0h2v4h4v2H6v4H4V6H0z" 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"/>
+ <path d="M6 11h1V7.1l.1-.1H11V5.1c.3-.1.7-.1 1-.1 3.9 0 7 3.1 7 7 0 1.4-.4 2.6-1.1 3.7L12 23l-5.9-7.3C5.4 14.6 5 13.4 5 12c0-.3 0-.7.1-1H6zm6 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
index 0246e4d3..72bbf347 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.png
+++ 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
index 61b8877f..3bda2450 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu-invert.svg
@@ -1,10 +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>
-<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>
+<?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="menu">
+ <path id="lines" d="M6 15.5h12c.6 0 1 .4 1 1v1c0 .6-.4 1-1 1H6c-.6 0-1-.4-1-1v-1c0-.6.4-1 1-1zm-1-4v1c0 .6.4 1 1 1h12c.6 0 1-.4 1-1v-1c0-.6-.4-1-1-1H6c-.6 0-1 .4-1 1zm0-5v1c0 .6.4 1 1 1h12c.6 0 1-.4 1-1v-1c0-.6-.4-1-1-1H6c-.6 0-1 .4-1 1z"/>
+ </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
index de7b1d24..45daeab4 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.png
+++ 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
index 89fd9789..b84ab866 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/menu.svg
@@ -1,10 +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">
-<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>
+<?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">
+ <path id="lines" d="M6 15.5h12c.6 0 1 .4 1 1v1c0 .6-.4 1-1 1H6c-.6 0-1-.4-1-1v-1c0-.6.4-1 1-1zm-1-4v1c0 .6.4 1 1 1h12c.6 0 1-.4 1-1v-1c0-.6-.4-1-1-1H6c-.6 0-1 .4-1 1zm0-5v1c0 .6.4 1 1 1h12c.6 0 1-.4 1-1v-1c0-.6-.4-1-1-1H6c-.6 0-1 .4-1 1z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr-invert.png
new file mode 100644
index 00000000..7e1c9fb9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr-invert.svg
new file mode 100644
index 00000000..c212285d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-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="M21 9c0-1.7-1.3-3-3-3H3v3l9 4 9-4zM3 11v6c0 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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.svg
index 3f308ff7..18387e18 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-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>
- <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"/>
+ <path d="M21 9c0-1.7-1.3-3-3-3H3v3l9 4 9-4zM3 11v6c0 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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl-invert.png
new file mode 100644
index 00000000..d9659792
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl-invert.svg
new file mode 100644
index 00000000..684b3040
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-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="g450">
+ <path d="M3 9c0-1.7 1.3-3 3-3h15v3l-9 4-9-4zm18 2v6c0 1.7-1.3 3-3 3H3v-9l9 4 9-4z" id="path452"/>
+ </g>
+</svg>
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
index fa61aa18..ff61048a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/message-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="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"/>
+ <path d="M3 9c0-1.7 1.3-3 3-3h15v3l-9 4-9-4zm18 2v6c0 1.7-1.3 3-3 3H3v-9l9 4 9-4z" id="path452"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/moon.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/moon.png
new file mode 100644
index 00000000..98df69c4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/moon.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/moon.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/moon.svg
new file mode 100644
index 00000000..45b00502
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/moon.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <path d="M19.1 17.5c-3.3 1.4-7.1-.2-8.5-3.5-1.4-3.3.2-7.1 3.5-8.5.2-.1.5-.2.7-.3-1.6-.4-3.2-.3-4.8.4C6 7.3 4 12 5.7 16c1.7 4.1 6.4 6 10.5 4.3 1.7-.7 3-1.9 3.8-3.4-.3.3-.6.4-.9.6z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-invert.png
new file mode 100644
index 00000000..e72516ab
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-invert.svg
new file mode 100644
index 00000000..5c7a7664
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-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 11l-4-3v2h-3V7h2l-3-4-3 4h2v3H8V8l-4 3 4 3v-2h3v3H9l3 4 3-4h-2v-3h3v2z"/>
+</svg>
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
index 10f0c4e5..fbebf0c4 100644
--- 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
@@ -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"><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"/>
+ <path id="arrow" d="M8.935 7.18l5.302 5.303-5.302 5.303L10.35 19.2l6.715-6.717-6.716-6.716z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-ltr.svg
index 51e6611a..670d84d1 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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">
- <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"/>
+ <path id="arrow" d="M8.935 7.18l5.302 5.303-5.302 5.303L10.35 19.2l6.715-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
index e97d37b9..db69b5a8 100644
--- 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
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
index 002ec0f6..9c859e4e 100644
--- 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
@@ -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"><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"/>
+ <path id="arrow" d="M15.065 17.786l-5.302-5.303 5.302-5.302-1.415-1.41-6.714 6.717L13.65 19.2z"/>
</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
index dbce05ec..7aab2175 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move-rtl.svg
index bcee09d9..35b63751 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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">
- <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"/>
+ <path id="arrow" d="M15.065 17.786l-5.302-5.303 5.302-5.302-1.415-1.41-6.714 6.717L13.65 19.2z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move.svg
index 9063bd48..b04ecdd4 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/move.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/move.svg
@@ -1,4 +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"/>
+ <path d="M20 11l-4-3v2h-3V7h2l-3-4-3 4h2v3H8V8l-4 3 4 3v-2h3v3H9l3 4 3-4h-2v-3h3v2z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr-invert.png
new file mode 100644
index 00000000..c1a9fab8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr-invert.svg
new file mode 100644
index 00000000..9febfff6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-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="g4">
+ <path d="M12 5l2.5 2.5L11 11c-1.2 1.2-1.2 2.8 0 4l5.5-5.5L19 12V5h-7zm5 12H8c-.6 0-1-.4-1-1V7h3L8 5H5v11c0 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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.svg
index b8ea833e..02e24f63 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-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="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"/>
+ <path d="M12 5l2.5 2.5L11 11c-1.2 1.2-1.2 2.8 0 4l5.5-5.5L19 12V5h-7zm5 12H8c-.6 0-1-.4-1-1V7h3L8 5H5v11c0 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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl-invert.png
new file mode 100644
index 00000000..8dd0188c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl-invert.svg
new file mode 100644
index 00000000..e72ecf50
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-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="g462">
+ <path d="M12 5L9.5 7.5 13 11c1.2 1.2 1.2 2.8 0 4L7.5 9.5 5 12V5h7zM7 17h9c.6 0 1-.4 1-1V7h-3l2-2h3v11c0 1.7-1.3 3-3 3H5v-3l2-2v3z" id="path464"/>
+ </g>
+</svg>
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
index 58a9eeb2..16ad8b43 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newWindow-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="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"/>
+ <path d="M12 5L9.5 7.5 13 11c1.2 1.2 1.2 2.8 0 4L7.5 9.5 5 12V5h7zM7 17h9c.6 0 1-.4 1-1V7h-3l2-2h3v11c0 1.7-1.3 3-3 3H5v-3l2-2v3z" id="path464"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr-invert.png
new file mode 100644
index 00000000..fb092271
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr-invert.svg
new file mode 100644
index 00000000..e0c1784f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-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="line_return">
+ <path d="M17.8 5.7c-.5 0-.9.2-1.2.5s-.5.7-.5 1.2v4.3H11v-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-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.png
index d4b638a2..9e7c67f9 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.png
+++ 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
index dad5f51c..1d654eb5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-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="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>
+ <g id="line_return">
+ <path d="M17.8 5.7c-.5 0-.9.2-1.2.5s-.5.7-.5 1.2v4.3H11v-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl-invert.png
new file mode 100644
index 00000000..11b6b25d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl-invert.svg
new file mode 100644
index 00000000..da6982b1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-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="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/newline-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl.svg
index fd758cc6..63e5aa14 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newline-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="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>
+ <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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr-invert.png
new file mode 100644
index 00000000..69ceeaf1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr-invert.svg
new file mode 100644
index 00000000..555eb59e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-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="M6 7v12c-.6 0-1-.4-1-1V9H4v9c0 1.1.9 2 2 2h15V7H6zm9 11H8v-1h7v1zm0-2H8v-1h7v1zm0-2H8v-1h7v1zm4 4h-3v-5h3v5zm0-7H8V9h11v2z"/>
+</svg>
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
index 46471a33..4ff58564 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-ltr.svg
@@ -1,4 +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"/>
+ <path d="M6 7v12c-.6 0-1-.4-1-1V9H4v9c0 1.1.9 2 2 2h15V7H6zm9 11H8v-1h7v1zm0-2H8v-1h7v1zm0-2H8v-1h7v1zm4 4h-3v-5h3v5zm0-7H8V9h11v2z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl-invert.png
new file mode 100644
index 00000000..c34589a7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl-invert.svg
new file mode 100644
index 00000000..71c59ef4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-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="M19 7v12c.6 0 1-.4 1-1V9h1v9c0 1.1-.9 2-2 2H4V7h15zm-9 11h7v-1h-7v1zm0-2h7v-1h-7v1zm0-2h7v-1h-7v1zm-4 4h3v-5H6v5zm0-7h11V9H6v2z" id="path474"/>
+</svg>
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
index 7564dff0..2c4a3211 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/newspaper-rtl.svg
@@ -1,4 +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"/>
+ <path d="M19 7v12c.6 0 1-.4 1-1V9h1v9c0 1.1-.9 2-2 2H4V7h15zm-9 11h7v-1h-7v1zm0-2h7v-1h-7v1zm0-2h7v-1h-7v1zm-4 4h3v-5H6v5zm0-7h11V9H6v2z" id="path474"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr-invert.png
new file mode 100644
index 00000000..dcd35cea
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr-invert.svg
new file mode 100644
index 00000000..770932b8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-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="M16 14l2 2V5h-4v2h2zm0 2L9 9 7 7 6 6 5 5 2 2 1 3l2 2H2v14h4v-2H4V7h1l2 2v10h4v-2H9v-6l6 6h-1v2h3l4 4 1-1-4-4zm-5-9V5H7l2 2zm8-2v2h2v10h-2l2 2h2V5z"/>
+ </g>
+</svg>
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
index 601428e2..e0e4fc01 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-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>
- <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"/>
+ <path d="M16 14l2 2V5h-4v2h2zm0 2L9 9 7 7 6 6 5 5 2 2 1 3l2 2H2v14h4v-2H4V7h1l2 2v10h4v-2H9v-6l6 6h-1v2h3l4 4 1-1-4-4zm-5-9V5H7l2 2zm8-2v2h2v10h-2l2 2h2V5z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl-invert.png
new file mode 100644
index 00000000..eda918c9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl-invert.svg
new file mode 100644
index 00000000..2ecb331c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-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="g484">
+ <path d="M8 14l-2 2V5h4v2H8zm0 2l7-7 2-2 1-1 1-1 3-3 1 1-2 2h1v14h-4v-2h2V7h-1l-2 2v10h-4v-2h2v-6l-6 6h1v2H7l-4 4-1-1 4-4zm5-9V5h4l-2 2zM5 5v2H3v10h2l-2 2H1V5z" id="path486"/>
+ </g>
+</svg>
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
index 31785a3c..a7be5abe 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/noWikiText-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="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"/>
+ <path d="M8 14l-2 2V5h4v2H8zm0 2l7-7 2-2 1-1 1-1 3-3 1 1-2 2h1v14h-4v-2h2V7h-1l-2 2v10h-4v-2h2v-6l-6 6h1v2H7l-4 4-1-1 4-4zm5-9V5h4l-2 2zM5 5v2H3v10h2l-2 2H1V5z" id="path486"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/notBright.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notBright.png
new file mode 100644
index 00000000..37145c76
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notBright.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/notBright.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notBright.svg
new file mode 100644
index 00000000..dedbc2d6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notBright.svg
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <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-8z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice-invert.png
new file mode 100644
index 00000000..ce1a278c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice-invert.svg
new file mode 100644
index 00000000..386ccc25
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice-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" id="svg3116"><style>* { fill: #FFFFFF }</style>
+ <g id="alert">
+ <path d="M12 18c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6zm-1-5h2V8h-2zm0 3h2v-2h-2z" id="path3119"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice.png
new file mode 100644
index 00000000..7d27f8e9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice.svg
new file mode 100644
index 00000000..9334b50e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/notice.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" id="svg3116">
+ <g id="alert">
+ <path d="M12 18c-3.314 0-6-2.686-6-6s2.686-6 6-6 6 2.686 6 6-2.686 6-6 6zm-1-5h2V8h-2zm0 3h2v-2h-2z" id="path3119"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-invert.png
new file mode 100644
index 00000000..5db6cf84
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-invert.svg
new file mode 100644
index 00000000..5385f32f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>* { fill: #FFFFFF }</style>
+ <g id="ongoing-conversation" fill-rule="evenodd">
+ <path d="M17.8 18.6H2.5l2.7-2.7V6h15.3v9.9c0 1.53-1.17 2.7-2.7 2.7zm-7.542-4.95c0 .405-.135.675-.405.945-.27.27-.607.405-.945.405-.405 0-.675-.135-.945-.405-.27-.27-.405-.607-.405-.945 0-.338.135-.675.405-.945.27-.27.608-.405.945-.405.338 0 .675.135.945.405.27.27.405.607.405.945zm4.05 0c0 .405-.135.675-.405.945-.27.27-.607.405-.945.405-.405 0-.675-.135-.945-.405-.27-.27-.405-.607-.405-.945 0-.338.135-.675.405-.945.27-.27.608-.405.945-.405.338 0 .675.135.945.405.27.27.405.607.405.945zm4.05 0c0 .405-.135.675-.405.945-.27.27-.607.405-.945.405-.405 0-.675-.135-.945-.405-.27-.27-.405-.607-.405-.945 0-.338.135-.675.405-.945.27-.27.608-.405.945-.405.338 0 .675.135.945.405.27.27.405.607.405.945z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-progressive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-progressive.png
new file mode 100644
index 00000000..62929778
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-progressive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-progressive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-progressive.svg
new file mode 100644
index 00000000..10390cd4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr-progressive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>* { fill: #347BFF }</style>
+ <g id="ongoing-conversation" fill-rule="evenodd">
+ <path d="M17.8 18.6H2.5l2.7-2.7V6h15.3v9.9c0 1.53-1.17 2.7-2.7 2.7zm-7.542-4.95c0 .405-.135.675-.405.945-.27.27-.607.405-.945.405-.405 0-.675-.135-.945-.405-.27-.27-.405-.607-.405-.945 0-.338.135-.675.405-.945.27-.27.608-.405.945-.405.338 0 .675.135.945.405.27.27.405.607.405.945zm4.05 0c0 .405-.135.675-.405.945-.27.27-.607.405-.945.405-.405 0-.675-.135-.945-.405-.27-.27-.405-.607-.405-.945 0-.338.135-.675.405-.945.27-.27.608-.405.945-.405.338 0 .675.135.945.405.27.27.405.607.405.945zm4.05 0c0 .405-.135.675-.405.945-.27.27-.607.405-.945.405-.405 0-.675-.135-.945-.405-.27-.27-.405-.607-.405-.945 0-.338.135-.675.405-.945.27-.27.608-.405.945-.405.338 0 .675.135.945.405.27.27.405.607.405.945z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr.png
new file mode 100644
index 00000000..eff32eb8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr.svg
new file mode 100644
index 00000000..5d4b3ac8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
+ <g id="ongoing-conversation" fill-rule="evenodd">
+ <path d="M17.8 18.6H2.5l2.7-2.7V6h15.3v9.9c0 1.53-1.17 2.7-2.7 2.7zm-7.542-4.95c0 .405-.135.675-.405.945-.27.27-.607.405-.945.405-.405 0-.675-.135-.945-.405-.27-.27-.405-.607-.405-.945 0-.338.135-.675.405-.945.27-.27.608-.405.945-.405.338 0 .675.135.945.405.27.27.405.607.405.945zm4.05 0c0 .405-.135.675-.405.945-.27.27-.607.405-.945.405-.405 0-.675-.135-.945-.405-.27-.27-.405-.607-.405-.945 0-.338.135-.675.405-.945.27-.27.608-.405.945-.405.338 0 .675.135.945.405.27.27.405.607.405.945zm4.05 0c0 .405-.135.675-.405.945-.27.27-.607.405-.945.405-.405 0-.675-.135-.945-.405-.27-.27-.405-.607-.405-.945 0-.338.135-.675.405-.945.27-.27.608-.405.945-.405.338 0 .675.135.945.405.27.27.405.607.405.945z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-invert.png
new file mode 100644
index 00000000..dd93100b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-invert.svg
new file mode 100644
index 00000000..451f247f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-invert.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>* { fill: #FFFFFF }</style>
+ <g id="ongoing-conversation" fill-rule="evenodd">
+ <path d="M5.2 18.6h15.3l-2.7-2.7V6H2.5v9.9c0 1.53 1.17 2.7 2.7 2.7zm7.542-4.95c0 .405.135.675.405.945.27.27.607.405.945.405.405 0 .675-.135.945-.405.27-.27.405-.607.405-.945 0-.337-.135-.675-.405-.945-.27-.27-.608-.405-.945-.405-.338 0-.675.135-.945.405-.27.27-.405.607-.405.945zm-4.05 0c0 .405.135.675.405.945.27.27.608.405.945.405.405 0 .675-.135.945-.405.27-.27.405-.607.405-.945 0-.337-.135-.675-.405-.945-.27-.27-.608-.405-.945-.405-.338 0-.675.135-.945.405-.27.27-.405.608-.405.945zm-4.05 0c0 .405.135.675.405.945.27.27.608.405.945.405.405 0 .675-.135.945-.405.27-.27.405-.607.405-.945 0-.337-.135-.675-.405-.945-.27-.27-.607-.405-.945-.405-.337 0-.675.135-.945.405-.27.27-.405.608-.405.945z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-progressive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-progressive.png
new file mode 100644
index 00000000..1afd9046
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-progressive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-progressive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-progressive.svg
new file mode 100644
index 00000000..b9494a0d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl-progressive.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><style>* { fill: #347BFF }</style>
+ <g id="ongoing-conversation" fill-rule="evenodd">
+ <path d="M5.2 18.6h15.3l-2.7-2.7V6H2.5v9.9c0 1.53 1.17 2.7 2.7 2.7zm7.542-4.95c0 .405.135.675.405.945.27.27.607.405.945.405.405 0 .675-.135.945-.405.27-.27.405-.607.405-.945 0-.337-.135-.675-.405-.945-.27-.27-.608-.405-.945-.405-.338 0-.675.135-.945.405-.27.27-.405.607-.405.945zm-4.05 0c0 .405.135.675.405.945.27.27.608.405.945.405.405 0 .675-.135.945-.405.27-.27.405-.607.405-.945 0-.337-.135-.675-.405-.945-.27-.27-.608-.405-.945-.405-.338 0-.675.135-.945.405-.27.27-.405.608-.405.945zm-4.05 0c0 .405.135.675.405.945.27.27.608.405.945.405.405 0 .675-.135.945-.405.27-.27.405-.607.405-.945 0-.337-.135-.675-.405-.945-.27-.27-.607-.405-.945-.405-.337 0-.675.135-.945.405-.27.27-.405.608-.405.945z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl.png
new file mode 100644
index 00000000..9a227673
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl.svg
new file mode 100644
index 00000000..9e5b7f6d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ongoingConversation-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
+ <g id="ongoing-conversation" fill-rule="evenodd">
+ <path d="M5.2 18.6h15.3l-2.7-2.7V6H2.5v9.9c0 1.53 1.17 2.7 2.7 2.7zm7.542-4.95c0 .405.135.675.405.945.27.27.607.405.945.405.405 0 .675-.135.945-.405.27-.27.405-.607.405-.945 0-.337-.135-.675-.405-.945-.27-.27-.608-.405-.945-.405-.338 0-.675.135-.945.405-.27.27-.405.607-.405.945zm-4.05 0c0 .405.135.675.405.945.27.27.608.405.945.405.405 0 .675-.135.945-.405.27-.27.405-.607.405-.945 0-.337-.135-.675-.405-.945-.27-.27-.608-.405-.945-.405-.338 0-.675.135-.945.405-.27.27-.405.608-.405.945zm-4.05 0c0 .405.135.675.405.945.27.27.608.405.945.405.405 0 .675-.135.945-.405.27-.27.405-.607.405-.945 0-.337-.135-.675-.405-.945-.27-.27-.607-.405-.945-.405-.337 0-.675.135-.945.405-.27.27-.405.608-.405.945z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr-invert.png
new file mode 100644
index 00000000..c552e53c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr-invert.svg
new file mode 100644
index 00000000..499f8aca
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-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="M10 8h9v2h-9V8zm0 3h9v2h-9v-2zm0 3h6v2h-6v-2zm11-8H3V4h18v2zm0 14H3v-2h18v2zM3 12l5 4V8l-5 4z"/>
+ </g>
+</svg>
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
index 4264ff08..d7181540 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-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>
- <path d="M10 8h9v2h-9v-2zm0 3h9v2h-9v-2zm0 3h6v2h-6v-2zm11-8h-18v-2h18v2zm0 14h-18v-2h18v2zm-18-8l5 4v-8l-5 4z"/>
+ <path d="M10 8h9v2h-9V8zm0 3h9v2h-9v-2zm0 3h6v2h-6v-2zm11-8H3V4h18v2zm0 14H3v-2h18v2zM3 12l5 4V8l-5 4z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl-invert.png
new file mode 100644
index 00000000..309681e9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl-invert.svg
new file mode 100644
index 00000000..597d1b7b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-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="g496">
+ <path d="M14 8H5v2h9V8zm0 3H5v2h9v-2zm0 3H8v2h6v-2zM3 6h18V4H3v2zm0 14h18v-2H3v2zm18-8l-5 4V8l5 4z" id="path498"/>
+ </g>
+</svg>
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
index 2479343e..b1a437f0 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outdent-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="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"/>
+ <path d="M14 8H5v2h9V8zm0 3H5v2h9v-2zm0 3H8v2h6v-2zM3 6h18V4H3v2zm0 14h18v-2H3v2zm18-8l-5 4V8l5 4z" id="path498"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr-invert.png
new file mode 100644
index 00000000..148a87e8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr-invert.svg
new file mode 100644
index 00000000..62d78e13
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr-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="outline-ltr">
+ <path id="text" d="M5 13h14v6H5v-6z"/>
+ <path id="float" d="M5 5v6h6V5H5zm5 5H6V6h4v4z"/>
+ </g>
+</svg>
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
index 9c0ea598..44c1591d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-ltr.svg
@@ -1,7 +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"/>
+ <path id="text" d="M5 13h14v6H5v-6z"/>
+ <path id="float" d="M5 5v6h6V5H5zm5 5H6V6h4v4z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl-invert.png
new file mode 100644
index 00000000..f30534fc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl-invert.svg
new file mode 100644
index 00000000..b992baf7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl-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="outline-rtl">
+ <path id="text" d="M19 19H5v-6h14v6z"/>
+ <path id="float" d="M13 5v6h6V5h-6zm1 1h4v4h-4V6z"/>
+ </g>
+</svg>
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
index 2a3428e9..c5b19c8f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/outline-rtl.svg
@@ -1,7 +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"/>
+ <path id="text" d="M19 19H5v-6h14v6z"/>
+ <path id="float" d="M13 5v6h6V5h-6zm1 1h4v4h-4V6z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr-invert.png
new file mode 100644
index 00000000..2c23c3c5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr-invert.svg
new file mode 100644
index 00000000..8647752b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-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="M2 3h18v2H4v12H2V3zm13 13l-4-4-4 5h13l-3-3-2 2zM5 6h17v13H5V6z"/>
+ </g>
+</svg>
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
index 92fc07ed..17eee176 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-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>
- <path d="M2 3h18v2h-16v12h-2v-14zm13 13l-4-4-4 5h13l-3-3-2 2zm-10-10h17v13h-17v-13z"/>
+ <path d="M2 3h18v2H4v12H2V3zm13 13l-4-4-4 5h13l-3-3-2 2zM5 6h17v13H5V6z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl-invert.png
new file mode 100644
index 00000000..ea51cad9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl-invert.svg
new file mode 100644
index 00000000..283bd5d0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-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="g508">
+ <path d="M22 3H4v2h16v12h2V3zM9 16l4-4 4 5H4l3-3 2 2zM19 6H2v13h17V6z" id="path510"/>
+ </g>
+</svg>
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
index d989d3d4..24a4e12b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/photoGallery-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="g508">
- <path d="M22 3h-18v2h16v12h2v-14zm-13 13l4-4 4 5h-13l3-3 2 2zm10-10h-17v13h17v-13z" id="path510"/>
+ <path d="M22 3H4v2h16v12h2V3zM9 16l4-4 4 5H4l3-3 2 2zM19 6H2v13h17V6z" 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
index d6dc62c4..f63756bc 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.png
+++ 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
index 55e0b7f1..a9699679 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture-invert.svg
@@ -1,8 +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"/>
+ <path id="frame" d="M4 5v13h16v-13zm15 12h-14v-11h14z"/>
+ <path id="mountains" d="M9.5 10l2.328 2.312-1.312 1.094.875 1.032 4.109-3.438 2.5 2v3h-12v-2.5z"/>
+ <path id="sky" d="M9.516 7.844l3.046 3.172 2.938-2.016 2.5 2v-4h-12v5z"/>
</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
index 20434248..d680396f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.svg
index 7400bca9..246e130c 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/picture.svg
@@ -1,8 +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="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"/>
+ <path id="frame" d="M4 5v13h16v-13zm15 12h-14v-11h14z"/>
+ <path id="mountains" d="M9.5 10l2.328 2.312-1.312 1.094.875 1.032 4.109-3.438 2.5 2v3h-12v-2.5z"/>
+ <path id="sky" d="M9.516 7.844l3.046 3.172 2.938-2.016 2.5 2v-4h-12v5z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr-invert.png
new file mode 100644
index 00000000..8a868846
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr-invert.svg
new file mode 100644
index 00000000..374312e2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-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="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 12V9l6 4-6 4z"/>
+ </g>
+</svg>
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
index 5ce95636..669e49de 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-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>
- <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"/>
+ <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 12V9l6 4-6 4z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl-invert.png
new file mode 100644
index 00000000..eb878daa
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl-invert.svg
new file mode 100644
index 00000000..6fc4664b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-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="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 12V9l-6 4 6 4z" id="path522"/>
+ </g>
+</svg>
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
index 591a5d3a..456fb4c7 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/play-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="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"/>
+ <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 12V9l-6 4 6 4z" id="path522"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr-invert.png
new file mode 100644
index 00000000..786beb1b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr-invert.svg
new file mode 100644
index 00000000..08c2c36e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-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 8h-1V4H7v4H3v6c0 1.7 1.3 3 3 3h1v3h10v-3h4v-6c0-1.7-1.3-3-3-3zM8 5h8v3H8V5zm8 14H8v-6h8v6z"/>
+</svg>
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
index baae35e9..7081606b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-ltr.svg
@@ -1,4 +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"/>
+ <path d="M18 8h-1V4H7v4H3v6c0 1.7 1.3 3 3 3h1v3h10v-3h4v-6c0-1.7-1.3-3-3-3zM8 5h8v3H8V5zm8 14H8v-6h8v6z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl-invert.png
new file mode 100644
index 00000000..bd37410b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl-invert.svg
new file mode 100644
index 00000000..19d6b2ec
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-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="M6 8h1V4h10v4h4v6c0 1.7-1.3 3-3 3h-1v3H7v-3H3v-6c0-1.7 1.3-3 3-3zm10-3H8v3h8V5zM8 19h8v-6H8v6z" id="path532"/>
+</svg>
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
index 8294afd5..79fd4e1f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/printer-rtl.svg
@@ -1,4 +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"/>
+ <path d="M6 8h1V4h10v4h4v6c0 1.7-1.3 3-3 3h-1v3H7v-3H3v-6c0-1.7 1.3-3 3-3zm10-3H8v3h8V5zM8 19h8v-6H8v6z" id="path532"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr-invert.png
new file mode 100644
index 00000000..4ad91604
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr-invert.svg
new file mode 100644
index 00000000..4e539692
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-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 9.9c-.7 0-1.4.3-1.8.9V6h-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.2H4.1v3.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-.1V18H9c-.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-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.png
index f6a9c860..47dad2bf 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.png
+++ 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
index 97b77bb4..0ea25d70 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-ltr.svg
@@ -1,4 +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"/>
+ <path d="M18 9.9c-.7 0-1.4.3-1.8.9V6h-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.2H4.1v3.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-.1V18H9c-.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl-invert.png
new file mode 100644
index 00000000..faff0aef
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl-invert.svg
new file mode 100644
index 00000000..715a5262
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-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="M6.3 9.9c.7 0 1.4.3 1.8.9V6h4c-.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-.1V18h-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.8H8.1v-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
index 03050e1c..51c40db8 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.png
+++ 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
index 0ad5f375..e6064255 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/puzzle-rtl.svg
@@ -1,4 +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"/>
+ <path d="M6.3 9.9c.7 0 1.4.3 1.8.9V6h4c-.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-.1V18h-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.8H8.1v-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr-invert.png
new file mode 100644
index 00000000..472bb4f7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr-invert.svg
new file mode 100644
index 00000000..9304bdb4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-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="g3226">
+ <path d="M18.1 8.65c.2-.1.5-.2.6-.5.1-.3.2-.5.2-.9v-.7c-1 .2-1.5.2-2.6.6-.7.4-1.2.9-1.7 1.4-.5.5-1.9 2.6-1.9 5.8v3.1h4.7c.9 0 1.6-.7 1.6-1.6v-4.7h-3.1s.1-.7.6-1.4c.5-.5 1-.9 1.6-1.1zm-11.2-.1c-.5.5-1.9 2.9-1.9 6v2.9h4.7c.9 0 1.6-.7 1.6-1.6v-4.7H8.2s.1-.7.6-1.4c.5-.5 1-.9 1.6-1.2.2-.1.5-.2.6-.5.1-.3.2-.5.2-.9v-.6c-1 .2-1.5.2-2.6.6-.6.4-1.2.9-1.7 1.4z" id="path3228"/>
+ </g>
+</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
index ffe3601d..72c7e3dd 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.png
+++ 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
index b3b923e5..4885f432 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-ltr.svg
@@ -1,11 +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">
-<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>
+<?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="g3226">
+ <path d="M18.1 8.65c.2-.1.5-.2.6-.5.1-.3.2-.5.2-.9v-.7c-1 .2-1.5.2-2.6.6-.7.4-1.2.9-1.7 1.4-.5.5-1.9 2.6-1.9 5.8v3.1h4.7c.9 0 1.6-.7 1.6-1.6v-4.7h-3.1s.1-.7.6-1.4c.5-.5 1-.9 1.6-1.1zm-11.2-.1c-.5.5-1.9 2.9-1.9 6v2.9h4.7c.9 0 1.6-.7 1.6-1.6v-4.7H8.2s.1-.7.6-1.4c.5-.5 1-.9 1.6-1.2.2-.1.5-.2.6-.5.1-.3.2-.5.2-.9v-.6c-1 .2-1.5.2-2.6.6-.6.4-1.2.9-1.7 1.4z" id="path3228"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl-invert.png
new file mode 100644
index 00000000..47fd687d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl-invert.svg
new file mode 100644
index 00000000..f5dcce50
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-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>
+ <path d="M5.9 8.65c-.2-.1-.5-.2-.6-.5-.1-.3-.2-.5-.2-.9v-.7c1 .2 1.5.2 2.6.6.7.4 1.2.9 1.7 1.4.5.5 1.9 2.6 1.9 5.8v3.1H6.6c-.9 0-1.6-.7-1.6-1.6v-4.7h3.1s-.1-.7-.6-1.4c-.5-.5-1-.9-1.6-1.1zm11.2-.1c.5.5 1.9 2.9 1.9 6v2.9h-4.7c-.9 0-1.6-.7-1.6-1.6v-4.7h3.1s-.1-.7-.6-1.4c-.5-.5-1-.9-1.6-1.2-.2-.1-.5-.2-.6-.5-.1-.3-.2-.5-.2-.9v-.6c1 .2 1.5.2 2.6.6.6.4 1.2.9 1.7 1.4z"/>
+ </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
index a2acf5e9..2b4c8d77 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.png
+++ 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
index b40a8ac9..91fe300d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotes-rtl.svg
@@ -1,11 +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">
-<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>
+<?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="M5.9 8.65c-.2-.1-.5-.2-.6-.5-.1-.3-.2-.5-.2-.9v-.7c1 .2 1.5.2 2.6.6.7.4 1.2.9 1.7 1.4.5.5 1.9 2.6 1.9 5.8v3.1H6.6c-.9 0-1.6-.7-1.6-1.6v-4.7h3.1s-.1-.7-.6-1.4c-.5-.5-1-.9-1.6-1.1zm11.2-.1c.5.5 1.9 2.9 1.9 6v2.9h-4.7c-.9 0-1.6-.7-1.6-1.6v-4.7h3.1s-.1-.7-.6-1.4c-.5-.5-1-.9-1.6-1.2-.2-.1-.5-.2-.6-.5-.1-.3-.2-.5-.2-.9v-.6c1 .2 1.5.2 2.6.6.6.4 1.2.9 1.7 1.4z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr-invert.png
new file mode 100644
index 00000000..1f7862e3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr-invert.svg
new file mode 100644
index 00000000..b08305e0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-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="g4">
+ <path d="M3.5 8.6C2.9 9.3 1 12 1 16v4h6c1.1 0 2-.9 2-2v-6H5s.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.1V6c-1.3.2-1.9.2-3.3.8-.8.5-1.6 1.1-2.2 1.8zM19 5V1h-2v4h-4v2h4v4h2V7h4V5zm-4 7s.1-.9.8-1.8l.2-.2V8h-1.9l-.6.6C12.9 9.3 11 12 11 16v4h6c1.1 0 2-.9 2-2v-6h-4z" id="path6"/>
+ </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
index b04ec747..7fd47541 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.png
+++ 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
index 24fca8f5..bacec22d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-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="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"/>
+ <path d="M3.5 8.6C2.9 9.3 1 12 1 16v4h6c1.1 0 2-.9 2-2v-6H5s.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.1V6c-1.3.2-1.9.2-3.3.8-.8.5-1.6 1.1-2.2 1.8zM19 5V1h-2v4h-4v2h4v4h2V7h4V5zm-4 7s.1-.9.8-1.8l.2-.2V8h-1.9l-.6.6C12.9 9.3 11 12 11 16v4h6c1.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl-invert.png
new file mode 100644
index 00000000..481db46d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl-invert.svg
new file mode 100644
index 00000000..a66bf474
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-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="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.1V6c1.3.2 1.9.2 3.3.8.8.5 1.6 1.1 2.2 1.8zM5 5V1h2v4h4v2H7v4H5V7H1V5zm4 7s-.1-.9-.8-1.8L8 10V8h1.9l.6.6c.6.7 2.5 3.4 2.5 7.4v4H7c-1.1 0-2-.9-2-2v-6h4z" 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
index 9e912026..e305696d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.png
+++ 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
index 736f2a6d..9aed41d3 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/quotesAdd-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="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"/>
+ <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.1V6c1.3.2 1.9.2 3.3.8.8.5 1.6 1.1 2.2 1.8zM5 5V1h2v4h4v2H7v4H5V7H1V5zm4 7s-.1-.9-.8-1.8L8 10V8h1.9l.6.6c.6.7 2.5 3.4 2.5 7.4v4H7c-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr-invert.png
new file mode 100644
index 00000000..066e17fc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr-invert.svg
new file mode 100644
index 00000000..0a4e04e8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-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="create_redirect">
+ <g>
+ <path d="M17.7 2.4c-.3-.3-.7-.4-1.2-.4H4.4v16.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-.6H6.4V16h5.4s-.4-1.5-.4-2h-5v-1h9v1c.4.1 1.1.1 1.5.1.4 0 .7 0 1.1-.1V3.5c.1-.5-.1-.9-.3-1.1zM12.5 4h3v4.5h-3V4zM6.4 4h4v1.6h-4V4zm0 3h4v1.5h-4V7zm0 3h9v1.5h-9V10zm12.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-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.png
index 3bca20fe..18ceb359 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.png
+++ 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
index 884d40df..be25d436 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-ltr.svg
@@ -2,7 +2,7 @@
<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"/>
+ <path d="M17.7 2.4c-.3-.3-.7-.4-1.2-.4H4.4v16.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-.6H6.4V16h5.4s-.4-1.5-.4-2h-5v-1h9v1c.4.1 1.1.1 1.5.1.4 0 .7 0 1.1-.1V3.5c.1-.5-.1-.9-.3-1.1zM12.5 4h3v4.5h-3V4zM6.4 4h4v1.6h-4V4zm0 3h4v1.5h-4V7zm0 3h9v1.5h-9V10zm12.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl-invert.png
new file mode 100644
index 00000000..cdcd1584
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl-invert.svg
new file mode 100644
index 00000000..431c5b8b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-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="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.7H7.8c.6-.2 1.2-.5 1.9-1 .4-.3.8-.6 1.2-1l.5-.6h6.2V16h-5.4s.4-1.5.4-2h5v-1h-9v1c-.4.1-1.1.1-1.5.1-.4 0-.7 0-1.1-.1V3.5c-.1-.5.1-.9.3-1.1zM11.5 4h-3v4.5h3V4zm6.1 0h-4v1.6h4V4zm0 3h-4v1.5h4V7zm0 3h-9v1.5h9V10z" id="path3266"/>
+ <path d="M4.9 13.1L0 16.9l4.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/redirect-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.svg
index a07e8364..a41d178f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/redirect-rtl.svg
@@ -2,8 +2,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"/>
+ <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.7H7.8c.6-.2 1.2-.5 1.9-1 .4-.3.8-.6 1.2-1l.5-.6h6.2V16h-5.4s.4-1.5.4-2h5v-1h-9v1c-.4.1-1.1.1-1.5.1-.4 0-.7 0-1.1-.1V3.5c-.1-.5.1-.9.3-1.1zM11.5 4h-3v4.5h3V4zm6.1 0h-4v1.6h4V4zm0 3h-4v1.5h4V7zm0 3h-9v1.5h9V10z" id="path3266"/>
+ <path d="M4.9 13.1L0 16.9l4.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression-invert.png
new file mode 100644
index 00000000..21b4d793
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression-invert.svg
new file mode 100644
index 00000000..5d2ff775
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression-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="regular-expression">
+ <path id="left-bracket" d="M3 12.045c0-.99.15-1.915.45-2.777.306-.862.743-1.618 1.314-2.268H6.23c-.552.72-.968 1.512-1.25 2.374-.28.862-.42 1.75-.42 2.66 0 .915.142 1.8.427 2.654.29.85.7 1.622 1.23 2.312h-1.45c-.575-.635-1.013-1.376-1.314-2.223-.3-.847-.45-1.758-.45-2.732"/>
+ <path id="dot" d="M10 16c0 .552-.448 1-1 1s-1-.448-1-1 .448-1 1-1 1 .448 1 1z"/>
+ <path id="star" d="M14.25 7.013l-.24 2.156 2.187-.61.193 1.474-1.992.14 1.307 1.74-1.33.71-.914-1.834-.8 1.823-1.382-.697 1.295-1.74-1.98-.152.23-1.465 2.14.61-.24-2.158h1.534"/>
+ <path id="right-bracket" d="M21 12.045c0 .982-.152 1.896-.457 2.744-.3.843-.737 1.58-1.307 2.21h-1.453c.527-.69.936-1.458 1.225-2.31.29-.854.434-1.74.434-2.66 0-.91-.14-1.796-.422-2.66-.28-.86-.697-1.653-1.248-2.373h1.465c.574.652 1.012 1.412 1.313 2.28.3.86.45 1.782.45 2.764"/>
+ </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
index 46439283..00ace192 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.png
+++ 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
index 7b672618..844013d3 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/regular-expression.svg
@@ -1,9 +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" />
+ <path id="left-bracket" d="M3 12.045c0-.99.15-1.915.45-2.777.306-.862.743-1.618 1.314-2.268H6.23c-.552.72-.968 1.512-1.25 2.374-.28.862-.42 1.75-.42 2.66 0 .915.142 1.8.427 2.654.29.85.7 1.622 1.23 2.312h-1.45c-.575-.635-1.013-1.376-1.314-2.223-.3-.847-.45-1.758-.45-2.732"/>
+ <path id="dot" d="M10 16c0 .552-.448 1-1 1s-1-.448-1-1 .448-1 1-1 1 .448 1 1z"/>
+ <path id="star" d="M14.25 7.013l-.24 2.156 2.187-.61.193 1.474-1.992.14 1.307 1.74-1.33.71-.914-1.834-.8 1.823-1.382-.697 1.295-1.74-1.98-.152.23-1.465 2.14.61-.24-2.158h1.534"/>
+ <path id="right-bracket" d="M21 12.045c0 .982-.152 1.896-.457 2.744-.3.843-.737 1.58-1.307 2.21h-1.453c.527-.69.936-1.458 1.225-2.31.29-.854.434-1.74.434-2.66 0-.91-.14-1.796-.422-2.66-.28-.86-.697-1.653-1.248-2.373h1.465c.574.652 1.012 1.412 1.313 2.28.3.86.45 1.782.45 2.764"/>
</g>
</svg>
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
index 3551e582..c242b8a4 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-destructive.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"><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"/>
+ <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0H9v6h1v-6zm4 0h-1v6h1v-6zm0-4V5H9v1H6v3h1v7.966l1 1.03v-.073V18h6.984l.016-.018v.015l1-1.03V9h1V6h-3zm1 11H8V9h7v8zm1-9H7V7h9v1z"/>
</g>
</svg>
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
index ddc352fe..0e2c8baf 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove-invert.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"><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"/>
+ <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0H9v6h1v-6zm4 0h-1v6h1v-6zm0-4V5H9v1H6v3h1v7.966l1 1.03v-.073V18h6.984l.016-.018v.015l1-1.03V9h1V6h-3zm1 11H8V9h7v8zm1-9H7V7h9v1z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/remove.svg
index 6ad79174..ef5f97b0 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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">
- <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"/>
+ <path id="trash-can" d="M12 10h-1v6h1v-6zm-2 0H9v6h1v-6zm4 0h-1v6h1v-6zm0-4V5H9v1H6v3h1v7.966l1 1.03v-.073V18h6.984l.016-.018v.015l1-1.03V9h1V6h-3zm1 11H8V9h7v8zm1-9H7V7h9v1z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize-invert.png
new file mode 100644
index 00000000..329da368
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize-invert.svg
new file mode 100644
index 00000000..d1d5e10b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize-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="Layer_1">
+ <g>
+ <circle cx="11.5" cy="8.5" r="2.5"/>
+ <path d="M16.3 8.7L17 8l-.8-.8.4-.8-1.1-.5.1-.9-1.2-.2-.1-.9-1.2.2-.4-.8-1.1.5L11 3l-.8.8-.9-.4-.5 1.1-.9-.2-.2 1.2-.9.2.2 1.2-.9.4.5 1.1L6 9l.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-1zM11.5 12C9.6 12 8 10.4 8 8.5S9.6 5 11.5 5 15 6.6 15 8.5 13.4 12 11.5 12zm.5 3l-.7-.7-1.1.6-.4-.7-.8.3V23l2.5-3 2.5 3v-8.5l-1-.5z"/>
+ </g>
+ </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
index ebce3c0b..304a4fab 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.png
+++ 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
index 6e4979f8..d15f387e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/ribbonPrize.svg
@@ -3,7 +3,7 @@
<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"/>
+ <path d="M16.3 8.7L17 8l-.8-.8.4-.8-1.1-.5.1-.9-1.2-.2-.1-.9-1.2.2-.4-.8-1.1.5L11 3l-.8.8-.9-.4-.5 1.1-.9-.2-.2 1.2-.9.2.2 1.2-.9.4.5 1.1L6 9l.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-1zM11.5 12C9.6 12 8 10.4 8 8.5S9.6 5 11.5 5 15 6.6 15 8.5 13.4 12 11.5 12zm.5 3l-.7-.7-1.1.6-.4-.7-.8.3V23l2.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
index 4b6ecd2f..555b641a 100644
--- 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
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
index 3d587833..41b0227f 100644
--- 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
@@ -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"><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"/>
+ <path id="magnifying-glass" d="M10.5 4C6.91 4 4 6.91 4 10.5S6.91 17 10.5 17c1.022 0 1.983-.236 2.844-.656L16 19c1.4 1.4 2.5 1.5 4 0l-4.438-4.438C16.462 13.447 17 12.044 17 10.5 17 6.91 14.09 4 10.5 4zm0 2c2.485 0 4.5 2.015 4.5 4.5S12.985 15 10.5 15 6 12.985 6 10.5 8.015 6 10.5 6z"/>
</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
index c10dc664..9f2033b9 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.png
+++ 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
index cdcbc30d..eadb088a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-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="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"/>
+ <path id="magnifying-glass" d="M10.5 4C6.91 4 4 6.91 4 10.5S6.91 17 10.5 17c1.022 0 1.983-.236 2.844-.656L16 19c1.4 1.4 2.5 1.5 4 0l-4.438-4.438C16.462 13.447 17 12.044 17 10.5 17 6.91 14.09 4 10.5 4zm0 2c2.485 0 4.5 2.015 4.5 4.5S12.985 15 10.5 15 6 12.985 6 10.5 8.015 6 10.5 6z"/>
</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
index 7868dc11..84197135 100644
--- 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
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
index 91130f08..8b143fc4 100644
--- 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
@@ -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"><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"/>
+ <path id="magnifying-glass" d="M13.5 4c3.59 0 6.5 2.91 6.5 6.5S17.09 17 13.5 17c-1.022 0-1.983-.236-2.844-.656L8 19c-1.4 1.4-2.5 1.5-4 0l4.438-4.438C7.538 13.447 7 12.044 7 10.5 7 6.91 9.91 4 13.5 4zm0 2C11.015 6 9 8.015 9 10.5s2.015 4.5 4.5 4.5 4.5-2.015 4.5-4.5S15.985 6 13.5 6z"/>
</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
index dab4ff14..c7bc7a89 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.png
+++ 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
index c6753493..d2e4585f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/search-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="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"/>
+ <path id="magnifying-glass" d="M13.5 4c3.59 0 6.5 2.91 6.5 6.5S17.09 17 13.5 17c-1.022 0-1.983-.236-2.844-.656L8 19c-1.4 1.4-2.5 1.5-4 0l4.438-4.438C7.538 13.447 7 12.044 7 10.5 7 6.91 9.91 4 13.5 4zm0 2C11.015 6 9 8.015 9 10.5s2.015 4.5 4.5 4.5 4.5-2.015 4.5-4.5S15.985 6 13.5 6z"/>
</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
index 0e9a5c57..2bb6e9d7 100644
--- 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
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
index 2aeba4ea..8660556d 100644
--- 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
@@ -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"><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"/>
+ <path id="lock" d="M8 5h.02v-.997c0-.057.003-1.41-.833-2.255-.434-.438-.998-.66-1.68-.66s-1.244.222-1.677.66c-.837.846-.833 2.198-.832 2.25V5H3c-.553 0-1 .447-1 1v3c0 .553.447 1 1 1h5c.553 0 1-.447 1-1V6c0-.553-.447-1-1-1zM3.998 5V3.993c0-.01.005-1 .543-1.543.486-.485 1.45-.487 1.936-.002.544.546.546 1.536.546 1.55V5H3.998z"/>
</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
index 918b3d7b..a2eba488 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.png
+++ 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
index a9c7d276..e064672f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/secure-link.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="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"/>
+ <path id="lock" d="M8 5h.02v-.997c0-.057.003-1.41-.833-2.255-.434-.438-.998-.66-1.68-.66s-1.244.222-1.677.66c-.837.846-.833 2.198-.832 2.25V5H3c-.553 0-1 .447-1 1v3c0 .553.447 1 1 1h5c.553 0 1-.447 1-1V6c0-.553-.447-1-1-1zM3.998 5V3.993c0-.01.005-1 .543-1.543.486-.485 1.45-.487 1.936-.002.544.546.546 1.536.546 1.55V5H3.998z"/>
</g>
</svg>
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
index c6eba159..34cc1900 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings-invert.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"><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"/>
+ <path id="gear" d="M3 4h3v2H3zm9 0h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1H8c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1zm-5 8h9v2H3zm15 0h3v2h-3zm-4-1h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2H3zm12 0h6v2h-6zm-4-1h2c.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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/settings.svg
index bcd665ee..37997674 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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">
- <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"/>
+ <path id="gear" d="M3 4h3v2H3zm9 0h9v2h-9zM8 3h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1H8c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1zm-5 8h9v2H3zm15 0h3v2h-3zm-4-1h2c.552 0 1 .448 1 1v2c0 .552-.448 1-1 1h-2c-.552 0-1-.448-1-1v-2c0-.552.448-1 1-1zM3 18h6v2H3zm12 0h6v2h-6zm-4-1h2c.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr-invert.png
new file mode 100644
index 00000000..c7776c07
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr-invert.svg
new file mode 100644
index 00000000..554525a7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-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="M0 20h24v1H0v-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 1H23c0-.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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.svg
index 0d495049..03b34cf8 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-ltr.svg
@@ -1,4 +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"/>
+ <path d="M0 20h24v1H0v-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 1H23c0-.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl-invert.png
new file mode 100644
index 00000000..5686bdbf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl-invert.svg
new file mode 100644
index 00000000..29620410
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-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="M24 20H0v1h24v-1zm-6-8l1-1 2 2 2-2 1 1-2 2 2 2-1 1-2-2-2 2-1-1 2-2zM2.4 15.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 1H1c0-.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/signature-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.png
index 3d9fb230..665c4e24 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.png
+++ 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
index 6c0ae5e0..97b2465f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/signature-rtl.svg
@@ -1,4 +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"/>
+ <path d="M24 20H0v1h24v-1zm-6-8l1-1 2 2 2-2 1 1-2 2 2 2-1 1-2-2-2 2-1-1 2-2zM2.4 15.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 1H1c0-.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr-invert.png
new file mode 100644
index 00000000..29675cfc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr-invert.svg
new file mode 100644
index 00000000..1126dba7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr-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>
+ <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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.svg
index e8b427b1..82d16af9 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-ltr.svg
@@ -1,7 +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>
+ <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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl-invert.png
new file mode 100644
index 00000000..20c2845b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl-invert.svg
new file mode 100644
index 00000000..ffac2da2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl-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>
+ <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/smaller-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.svg
index e5e95196..7466f48b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smaller-rtl.svg
@@ -1,7 +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>
+ <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/smallerText-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-ltr.png
new file mode 100644
index 00000000..63551b44
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-ltr.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-ltr.svg
new file mode 100644
index 00000000..b3d2e944
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-ltr.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M17.6 20h-5.4v-.5c.2 0 .5-.1.9-.1.3-.1.5-.2.5-.3V19s0-.1-.1-.2l-.8-2H9.3c-.1.2-.2.4-.3.7-.1.3-.2.5-.2.7-.1.3-.1.4-.2.6v.2c0 .1.1.3.3.4.2.1.6.2 1.1.2v.4H6v-.5c.2 0 .3 0 .5-.1.2 0 .3-.1.5-.2s.4-.2.5-.4l.3-.6c.5-1.3 1.1-2.6 1.6-3.9.5-1.3 1.1-2.7 1.8-4.3h1.4c.9 2.2 1.6 4 2.1 5.3.5 1.3 1 2.4 1.3 3.2.1.1.1.3.2.4.1.1.2.2.4.3.1.1.3.1.5.2s.3.1.5.1v.5zm-5.2-4L11 12.4 9.6 16h2.8z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-rtl.png
new file mode 100644
index 00000000..a245556e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-rtl.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-rtl.svg
new file mode 100644
index 00000000..34d46bce
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/smallerText-rtl.svg
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24">
+ <g>
+ <path d="M6 19.5c.1 0 .3 0 .5-.1s.3-.1.5-.2.3-.2.4-.3c.1-.1.2-.2.2-.4.4-.9.8-1.9 1.3-3.2.5-1.3 1.2-3.1 2.1-5.3h1.4c.7 1.6 1.2 3 1.8 4.3.5 1.3 1.1 2.6 1.6 3.9l.3.6c.1.2.3.3.5.4.1.1.3.1.5.2.2 0 .4.1.5.1v.5h-4v-.5c.5 0 .9-.1 1.1-.2.2-.1.3-.2.3-.4v-.2c0-.1-.1-.3-.2-.6-.1-.2-.2-.4-.2-.7-.1-.3-.2-.5-.3-.7h-3.4l-.8 2c0 .1-.1.1-.1.2v.1c0 .1.2.2.5.3.3.1.6.1.9.1v.6H6v-.5zm8-3.5l-1.4-3.6-1.4 3.6H14z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter-invert.png
new file mode 100644
index 00000000..008efd04
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter-invert.svg
new file mode 100644
index 00000000..5f3d9147
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter-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="special-character">
+ <path id="omega" d="M12 6.708c-.794 0-1.368.103-1.894.31-.525.207-.944.496-1.255.867-.31.366-.53.808-.66 1.327-.124.513-.19 1.08-.19 1.7 0 .512.06 1 .176 1.46.122.46.31.87.568 1.23.63.862 1.156 1.138 2.012 1.362L11 18H6v-3h.604l.53 1.353.395.053.6.044.75.035.458.01H10l-.09-.895c-.63-.094-.812-.268-1.337-.522-.525-.26-.98-.59-1.365-.99-.38-.402-.675-.868-.89-1.4-.213-.536-.32-1.13-.32-1.778 0-.82.13-1.537.394-2.15.27-.62.656-1.133 1.163-1.54.507-.407 1.133-.71 1.878-.912.745-.206 1.6-.31 2.565-.31.96 0 1.81.103 2.556.31.75.2 1.38.504 1.887.912.51.407.896.92 1.158 1.54.27.614.403 1.33.403 2.15 0 .65-.107 1.242-.32 1.78-.215.53-.514.996-.9 1.397-.38.4-.83.732-1.355.99-.525.255-.707.43-1.336.523l-.093.894h.66l.447-.01.75-.034.606-.044.4-.053.533-1.354H18v3h-5l.246-3.04c1.066-.11 1.337-.695 2.002-1.362.263-.36.452-.77.568-1.23.122-.46.183-.947.183-1.46 0-.62-.067-1.186-.195-1.7-.128-.52-.348-.96-.66-1.326-.31-.372-.73-.66-1.255-.867-.524-.206-1.1-.31-1.893-.31"/>
+ </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
index 51ccb89c..7f658819 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.png
+++ 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
index 4d601281..dbf6ed5a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/specialCharacter.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="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"/>
+ <path id="omega" d="M12 6.708c-.794 0-1.368.103-1.894.31-.525.207-.944.496-1.255.867-.31.366-.53.808-.66 1.327-.124.513-.19 1.08-.19 1.7 0 .512.06 1 .176 1.46.122.46.31.87.568 1.23.63.862 1.156 1.138 2.012 1.362L11 18H6v-3h.604l.53 1.353.395.053.6.044.75.035.458.01H10l-.09-.895c-.63-.094-.812-.268-1.337-.522-.525-.26-.98-.59-1.365-.99-.38-.402-.675-.868-.89-1.4-.213-.536-.32-1.13-.32-1.778 0-.82.13-1.537.394-2.15.27-.62.656-1.133 1.163-1.54.507-.407 1.133-.71 1.878-.912.745-.206 1.6-.31 2.565-.31.96 0 1.81.103 2.556.31.75.2 1.38.504 1.887.912.51.407.896.92 1.158 1.54.27.614.403 1.33.403 2.15 0 .65-.107 1.242-.32 1.78-.215.53-.514.996-.9 1.397-.38.4-.83.732-1.355.99-.525.255-.707.43-1.336.523l-.093.894h.66l.447-.01.75-.034.606-.044.4-.053.533-1.354H18v3h-5l.246-3.04c1.066-.11 1.337-.695 2.002-1.362.263-.36.452-.77.568-1.23.122-.46.183-.947.183-1.46 0-.62-.067-1.186-.195-1.7-.128-.52-.348-.96-.66-1.326-.31-.372-.73-.66-1.255-.867-.524-.206-1.1-.31-1.893-.31"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr-invert.png
new file mode 100644
index 00000000..15ae3abc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr-invert.svg
new file mode 100644
index 00000000..8f0d6e1a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-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="M19 20H2l3-3V6h17v11c0 1.7-1.3 3-3 3z"/>
+ </g>
+</svg>
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
index f3fb8b31..6e5eacd9 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-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>
- <path d="M19 20h-17l3-3v-11h17v11c0 1.7-1.3 3-3 3z"/>
+ <path d="M19 20H2l3-3V6h17v11c0 1.7-1.3 3-3 3z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl-invert.png
new file mode 100644
index 00000000..02c0fa1c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl-invert.svg
new file mode 100644
index 00000000..4eaf3311
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-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="g586">
+ <path d="M5 20h17l-3-3V6H2v11c0 1.7 1.3 3 3 3z" id="path588"/>
+ </g>
+</svg>
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
index fd9b7bd9..139c34ea 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubble-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="g586">
- <path d="M5 20h17l-3-3v-11h-17v11c0 1.7 1.3 3 3 3z" id="path588"/>
+ <path d="M5 20h17l-3-3V6H2v11c0 1.7 1.3 3 3 3z" id="path588"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr-invert.png
new file mode 100644
index 00000000..15ae3abc
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr-invert.svg
new file mode 100644
index 00000000..652bb0b3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr-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>
+ <path d="M19 20H2l3-3V6h17v11c0 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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg
index 333c1e86..054c0bed 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-ltr.svg
@@ -1,7 +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"/>
+ <path d="M19 20H2l3-3V6h17v11c0 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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl-invert.png
new file mode 100644
index 00000000..02c0fa1c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl-invert.svg
new file mode 100644
index 00000000..b5718ef2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl-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="g598">
+ <path d="M5 20h17l-3-3V6H2v11c0 1.7 1.3 3 3 3z" id="path600"/>
+ </g>
+ <path d="M11 9h-1v7h1zm3 3H7v1h7z" id="path602" fill="#fff"/>
+</svg>
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
index 4e6313f1..c822ec53 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbleAdd-rtl.svg
@@ -1,7 +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"/>
+ <path d="M5 20h17l-3-3V6H2v11c0 1.7 1.3 3 3 3z" id="path600"/>
</g>
- <path d="M11 9h-1v7h1zm3 3h-7v1h7z" id="path602" fill="#fff"/>
+ <path d="M11 9h-1v7h1zm3 3H7v1h7z" id="path602" fill="#fff"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr-invert.png
new file mode 100644
index 00000000..405f8ed2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr-invert.svg
new file mode 100644
index 00000000..f07ce026
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-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 9v9l2 2H8V9h12zM3 4h12v4H7v7H1l2-2V4z"/>
+ </g>
+</svg>
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
index c4b4a2f7..9c1c3f84 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-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>
- <path d="M20 9v9l2 2h-14v-11h12zm-17-5h12v4h-8v7h-6l2-2v-9z"/>
+ <path d="M20 9v9l2 2H8V9h12zM3 4h12v4H7v7H1l2-2V4z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl-invert.png
new file mode 100644
index 00000000..6350811a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl-invert.svg
new file mode 100644
index 00000000..b98ed2b4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-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="g612">
+ <path d="M3 9v9l-2 2h14V9H3zm17-5H8v4h8v7h6l-2-2V4z" id="path614"/>
+ </g>
+</svg>
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
index c452fbbd..49fc3d3f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/speechBubbles-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="g612">
- <path d="M3 9v9l-2 2h14v-11h-12zm17-5h-12v4h8v7h6l-2-2v-9z" id="path614"/>
+ <path d="M3 9v9l-2 2h14V9H3zm17-5H8v4h8v7h6l-2-2V4z" id="path614"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-constructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-constructive.png
new file mode 100644
index 00000000..b0bc3b1e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-constructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-constructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-constructive.svg
new file mode 100644
index 00000000..9e64bcfb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-constructive.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: #00AF89 }</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-.5L12 7.4M12 4L9.2 9.6l-6.2.9 4.5 4.4L6.4 21l5.6-3 5.5 3-1-6.2 4.5-4.4-6.3-.9L12 4z"/>
+</svg>
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
index f58e8ce5..af066365 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star-invert.svg
@@ -1,4 +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"/>
+ <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-.5L12 7.4M12 4L9.2 9.6l-6.2.9 4.5 4.4L6.4 21l5.6-3 5.5 3-1-6.2 4.5-4.4-6.3-.9L12 4z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/star.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star.svg
index ea8c26c6..54ba77ad 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/star.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/star.svg
@@ -1,4 +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"/>
+ <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-.5L12 7.4M12 4L9.2 9.6l-6.2.9 4.5 4.4L6.4 21l5.6-3 5.5 3-1-6.2 4.5-4.4-6.3-.9L12 4z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop-invert.png
new file mode 100644
index 00000000..c2a07c63
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop-invert.svg
new file mode 100644
index 00000000..ef7b7c6d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop-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 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 5h6v6H9z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.svg
index 7bd06331..aa25e3d4 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stop.svg
@@ -1,4 +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"/>
+ <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 5h6v6H9z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a-invert.png
new file mode 100644
index 00000000..bf6e28fd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a-invert.svg
new file mode 100644
index 00000000..60b36a8b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a-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="strikethrough-a">
+ <path id="strikethrough" d="M6 11h12v1H6v-1z"/>
+ <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>
+</svg>
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
index 480189f5..070d7853 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-a.svg
@@ -1,7 +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"/>
+ <path id="strikethrough" d="M6 11h12v1H6v-1z"/>
+ <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>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s-invert.png
new file mode 100644
index 00000000..a80ee258
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s-invert.svg
new file mode 100644
index 00000000..fd1c16d3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s-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="strikethrough-s">
+ <path id="strikethrough" d="M6 12h12v1H6v-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 .89.22 1.602.72 2.13.497.528 1.278.91 2.31 1.14l.813.182v-.03c.656.147 1.128.375 1.375.63.252.256.375.607.375 1.11 0 .573-.172.97-.53 1.26-.36.29-.895.45-1.626.45-.473 0-.965-.074-1.465-.24-.502-.166-1.03-.417-1.562-.75l-.374-.238v2.158l.155.062c.58.237 1.144.417 1.69.54.548.12 1.07.18 1.56.18 1.287 0 2.298-.293 3-.9.71-.605 1.063-1.486 1.063-2.608 0-.943-.256-1.726-.78-2.312-.522-.592-1.306-1-2.345-1.23l-.812-.18c-.715-.148-1.203-.352-1.405-.54-.205-.202-.312-.484-.312-.934 0-.533.162-.9.5-1.17.342-.27.836-.42 1.53-.42.396 0 .82.052 1.25.18.434.128.91.334 1.407.6l.374.18V6.63s-1.188-.383-1.688-.48c-.5-.097-.984-.15-1.468-.15z"/>
+ </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
index 8aafe3f6..1bcb55bd 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.png
+++ 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
index d57b652f..46092a6b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-s.svg
@@ -1,7 +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"/>
+ <path id="strikethrough" d="M6 12h12v1H6v-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 .89.22 1.602.72 2.13.497.528 1.278.91 2.31 1.14l.813.182v-.03c.656.147 1.128.375 1.375.63.252.256.375.607.375 1.11 0 .573-.172.97-.53 1.26-.36.29-.895.45-1.626.45-.473 0-.965-.074-1.465-.24-.502-.166-1.03-.417-1.562-.75l-.374-.238v2.158l.155.062c.58.237 1.144.417 1.69.54.548.12 1.07.18 1.56.18 1.287 0 2.298-.293 3-.9.71-.605 1.063-1.486 1.063-2.608 0-.943-.256-1.726-.78-2.312-.522-.592-1.306-1-2.345-1.23l-.812-.18c-.715-.148-1.203-.352-1.405-.54-.205-.202-.312-.484-.312-.934 0-.533.162-.9.5-1.17.342-.27.836-.42 1.53-.42.396 0 .82.052 1.25.18.434.128.91.334 1.407.6l.374.18V6.63s-1.188-.383-1.688-.48c-.5-.097-.984-.15-1.468-.15z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y-invert.png
new file mode 100644
index 00000000..63028d6d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y-invert.svg
new file mode 100644
index 00000000..50db67bb
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y-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="strikethrough-y">
+ <path id="strikethrough" d="M6 11h12v1H6v-1z"/>
+ <path id="a" d="M7 6h1.724l3.288 4.935L15.276 6H17l-4.194 6.285V18h-1.612v-5.715L7 6"/>
+ </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
index a0065cbb..5b1c1fd5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.png
+++ 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
index 8409dc15..2fdbc871 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/strikethrough-y.svg
@@ -1,7 +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"/>
+ <path id="strikethrough" d="M6 11h12v1H6v-1z"/>
+ <path id="a" d="M7 6h1.724l3.288 4.935L15.276 6H17l-4.194 6.285V18h-1.612v-5.715L7 6"/>
</g>
</svg>
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
index 4fbd4ecd..97aacad9 100644
--- 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
@@ -1,4 +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"/>
+ <path d="M4 9h12v2H4V9zm0 3h8v2H4v-2zm0-7h16v3H4V5zm16 14H4v-3h16v3z"/>
</svg>
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
index acacc362..2112bb2d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-ltr.svg
@@ -1,4 +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"/>
+ <path d="M4 9h12v2H4V9zm0 3h8v2H4v-2zm0-7h16v3H4V5zm16 14H4v-3h16v3z"/>
</svg>
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
index b18ddc46..8187dba8 100644
--- 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
@@ -1,4 +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"/>
+ <path d="M20 9H8v2h12V9zm0 3h-8v2h8v-2zm0-7H4v3h16V5zM4 19h16v-3H4v3z" id="path624"/>
</svg>
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
index c38a283f..f34bec25 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeFlow-rtl.svg
@@ -1,4 +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"/>
+ <path d="M20 9H8v2h12V9zm0 3h-8v2h8v-2zm0-7H4v3h16V5zM4 19h16v-3H4v3z" id="path624"/>
</svg>
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
index 47eff5dd..9b7bba91 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu-invert.svg
@@ -1,12 +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"/>
+ <path d="M20 19H4v-2h16v2z"/>
</g>
<g>
- <path d="M20 15h-16v-2h16v2z"/>
+ <path d="M20 15H4v-2h16v2z"/>
</g>
<g>
- <path d="M20 11h-16v-2h16v2z"/>
+ <path d="M20 11H4V9h16v2z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.svg
index 47e70d74..ea40dde8 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSideMenu.svg
@@ -1,12 +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"/>
+ <path d="M20 19H4v-2h16v2z"/>
</g>
<g>
- <path d="M20 15h-16v-2h16v2z"/>
+ <path d="M20 15H4v-2h16v2z"/>
</g>
<g>
- <path d="M20 11h-16v-2h16v2z"/>
+ <path d="M20 11H4V9h16v2z"/>
</g>
</svg>
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
index d694cb15..a59f0d96 100644
--- 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
@@ -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"><style>* { fill: #FFFFFF }</style>
<g>
- <path d="M20 11h-16v-2h16v2zm-16 1h8v2h-8v-2z"/>
+ <path d="M20 11H4V9h16v2zM4 12h8v2H4v-2z"/>
</g>
</svg>
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
index 7f8822bc..a924c9c8 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-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>
- <path d="M20 11h-16v-2h16v2zm-16 1h8v2h-8v-2z"/>
+ <path d="M20 11H4V9h16v2zM4 12h8v2H4v-2z"/>
</g>
</svg>
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
index 86a52ee8..391597c8 100644
--- 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
@@ -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"><style>* { fill: #FFFFFF }</style>
<g id="g654">
- <path d="M4 11h16v-2h-16v2zm16 1h-8v2h8v-2z" id="path656"/>
+ <path d="M4 11h16V9H4v2zm16 1h-8v2h8v-2z" id="path656"/>
</g>
</svg>
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
index fcb10bad..1da4bd91 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeSummary-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="g654">
- <path d="M4 11h16v-2h-16v2zm16 1h-8v2h8v-2z" id="path656"/>
+ <path d="M4 11h16V9H4v2zm16 1h-8v2h8v-2z" id="path656"/>
</g>
</svg>
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
index d2e9786e..8710bd32 100644
--- 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
@@ -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"><style>* { fill: #FFFFFF }</style>
<g>
- <path d="M17 13h-13v-3h13v3zm-5 6h-8v-3h8v3zm-8-12v-3h16v3h-16z"/>
+ <path d="M17 13H4v-3h13v3zm-5 6H4v-3h8v3zM4 7V4h16v3H4z"/>
</g>
</svg>
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
index be303204..b16a94bb 100644
--- 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
@@ -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"><style>* { fill: #347BFF }</style>
<g>
- <path d="M17 13h-13v-3h13v3zm-5 6h-8v-3h8v3zm-8-12v-3h16v3h-16z"/>
+ <path d="M17 13H4v-3h13v3zm-5 6H4v-3h8v3zM4 7V4h16v3H4z"/>
</g>
</svg>
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
index 76c80d20..21ed0eaf 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-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>
- <path d="M17 13h-13v-3h13v3zm-5 6h-8v-3h8v3zm-8-12v-3h16v3h-16z"/>
+ <path d="M17 13H4v-3h13v3zm-5 6H4v-3h8v3zM4 7V4h16v3H4z"/>
</g>
</svg>
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
index 6266319d..9dc9a547 100644
--- 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
@@ -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"><style>* { fill: #FFFFFF }</style>
<g id="g666">
- <path d="M7 13h13v-3h-13v3zm5 6h8v-3h-8v3zm8-12v-3h-16v3h16z" id="path668"/>
+ <path d="M7 13h13v-3H7v3zm5 6h8v-3h-8v3zm8-12V4H4v3h16z" id="path668"/>
</g>
</svg>
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
index c5847b1f..7485ba08 100644
--- 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
@@ -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"><style>* { fill: #347BFF }</style>
<g id="g666">
- <path d="M7 13h13v-3h-13v3zm5 6h8v-3h-8v3zm8-12v-3h-16v3h16z" id="path668"/>
+ <path d="M7 13h13v-3H7v3zm5 6h8v-3h-8v3zm8-12V4H4v3h16z" id="path668"/>
</g>
</svg>
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
index 308c2e62..14b2f8cb 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/stripeToC-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="g666">
- <path d="M7 13h13v-3h-13v3zm5 6h8v-3h-8v3zm8-12v-3h-16v3h16z" id="path668"/>
+ <path d="M7 13h13v-3H7v3zm5 6h8v-3h-8v3zm8-12V4H4v3h16z" id="path668"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr-invert.png
new file mode 100644
index 00000000..1607d399
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr-invert.svg
new file mode 100644
index 00000000..b5ef54ec
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr-invert.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"><style>* { fill: #FFFFFF }</style>
+ <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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.svg
index b7507daf..fbb0c3c3 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-ltr.svg
@@ -1,5 +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"/>
+ <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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl-invert.png
new file mode 100644
index 00000000..3970bb12
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl-invert.svg
new file mode 100644
index 00000000..e43eac6a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl-invert.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"><style>* { fill: #FFFFFF }</style>
+ <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/subscript-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.svg
index 9fe5325f..91a71ecc 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/subscript-rtl.svg
@@ -1,5 +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"/>
+ <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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr-invert.png
new file mode 100644
index 00000000..9c2fe07d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr-invert.svg
new file mode 100644
index 00000000..7f7ef3a9
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr-invert.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"><style>* { fill: #FFFFFF }</style>
+ <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-5V2.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.3zM6.2 4.9c.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.2H3.2c0-.3.1-.6.4-.9s.5-.3.8-.3zM6.2 16l1.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-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.png
index 1f829c1b..459f4c95 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.png
+++ 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
index f1b7caf3..4bde1836 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-ltr.svg
@@ -1,5 +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"/>
+ <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-5V2.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.3zM6.2 4.9c.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.2H3.2c0-.3.1-.6.4-.9s.5-.3.8-.3zM6.2 16l1.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl-invert.png
new file mode 100644
index 00000000..3481d180
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl-invert.svg
new file mode 100644
index 00000000..f90bc0c8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl-invert.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"><style>* { fill: #FFFFFF }</style>
+ <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.3H3.2c0 .3.1.6.4.9.3.3.5.4.8.4h2v-1.3zm6.2-5V2.2c-.3 0-.6.1-.9.4-.3.3-.4.5-.4.8v2h1.3zM6.2 17.1c.3 0 .6-.1.8-.3l1.4-1.4-.8-.8-2.2 2.2c.2.2.5.3.8.3zM17.8 4.9c-.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-.3zM17.8 16l-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/sun-rtl.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.png
index 1e6f362f..8a0fc83c 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.png
+++ 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
index a625fb90..2570610a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/sun-rtl.svg
@@ -1,5 +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"/>
+ <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.3H3.2c0 .3.1.6.4.9.3.3.5.4.8.4h2v-1.3zm6.2-5V2.2c-.3 0-.6.1-.9.4-.3.3-.4.5-.4.8v2h1.3zM6.2 17.1c.3 0 .6-.1.8-.3l1.4-1.4-.8-.8-2.2 2.2c.2.2.5.3.8.3zM17.8 4.9c-.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-.3zM17.8 16l-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr-invert.png
new file mode 100644
index 00000000..7099d7f4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr-invert.svg
new file mode 100644
index 00000000..7f95dcf1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr-invert.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"><style>* { fill: #FFFFFF }</style>
+ <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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.svg
index 39f30a76..45abfda2 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-ltr.svg
@@ -1,5 +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"/>
+ <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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl-invert.png
new file mode 100644
index 00000000..7d73f51d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl-invert.svg
new file mode 100644
index 00000000..468316dd
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl-invert.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"><style>* { fill: #FFFFFF }</style>
+ <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/superscript-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.svg
index eabab21c..33b5814b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/superscript-rtl.svg
@@ -1,5 +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"/>
+ <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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption-invert.png
new file mode 100644
index 00000000..81c258ed
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption-invert.svg
new file mode 100644
index 00000000..39236146
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption-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="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-caption.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.svg
index 15bb06a6..6b7edc6f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-caption.svg
@@ -1,7 +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"/>
+ <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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr-invert.png
new file mode 100644
index 00000000..13bb4213
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr-invert.svg
new file mode 100644
index 00000000..1bb2d7e7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-ltr-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="table-insert-column-ltr">
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M5 5h2v14H5z" id="column"/>
+ </g>
+</svg>
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
index 798ee4a1..a67ed201 100644
--- 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
@@ -1,11 +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-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" />
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M5 5h2v14H5z" id="column"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl-invert.png
new file mode 100644
index 00000000..363241b6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl-invert.svg
new file mode 100644
index 00000000..8489597a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-column-rtl-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="table-insert-column-rtl">
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M17 5h2v14h-2z" id="column"/>
+ </g>
+</svg>
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
index dfa33a08..dee782e9 100644
--- 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
@@ -1,11 +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-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" />
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M17 5h2v14h-2z" id="column"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after-invert.png
new file mode 100644
index 00000000..eb82a503
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after-invert.svg
new file mode 100644
index 00000000..d0813a6d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-after-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="table-insert-row-after">
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M5 17h14v2H5z" id="row"/>
+ </g>
+</svg>
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
index 91d06644..ad9d86db 100644
--- 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
@@ -1,11 +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-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" />
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M5 17h14v2H5z" id="row"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before-invert.png
new file mode 100644
index 00000000..f5ff5405
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before-invert.svg
new file mode 100644
index 00000000..516078f0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-insert-row-before-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="table-insert-row-before">
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M5 5h14v2H5z" id="row"/>
+ </g>
+</svg>
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
index 4b71f2a8..e9dfe048 100644
--- 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
@@ -1,11 +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-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" />
+ <path d="M13 9h-2v2H9v2h2v2h2v-2h2v-2h-2z" id="plus"/>
+ <path d="M5 5h14v2H5z" id="row"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-invert.png
new file mode 100644
index 00000000..ee9885f6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-invert.svg
new file mode 100644
index 00000000..808d8d8d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-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="table-insert">
+ <path id="table" d="M4 6v11h15V6zm1 3h6v3H5zm7 0h6v3h-6zm-7 4h6v3H5zm7 0h6v3h-6z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells-invert.png
new file mode 100644
index 00000000..67c095d8
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells-invert.svg
new file mode 100644
index 00000000..06cb4daa
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells-invert.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"><style>* { fill: #FFFFFF }</style>
+ <g id="table-merge-cells">
+ <g id="merge-cell-left">
+ <path id="cell-border" d="M4 7v9h7v-3l-1 .834V15H5V8h5v1.167L11 10V7z"/>
+ <path id="arrow" d="M8 9v2H6v1h2v2l3-2.5z"/>
+ </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-merge-cells.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table-merge-cells.svg
index 6a8b77d8..3ffb9e5e 100644
--- 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
@@ -1,10 +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 id="table-merge-cells">
+ <g id="merge-cell-left">
+ <path id="cell-border" d="M4 7v9h7v-3l-1 .834V15H5V8h5v1.167L11 10V7z"/>
+ <path id="arrow" d="M8 9v2H6v1h2v2l3-2.5z"/>
+ </g>
+ <use id="merge-cell-right" xlink:href="#merge-cell-left" transform="matrix(-1 0 0 1 24 0)"/>
</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
index fb6b985b..2eedd1e3 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table.png
+++ 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
index 1ba8c440..b5733fba 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/table.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/table.svg
@@ -1,7 +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="table-insert">
- <path id="table" d="M4 5v13h16v-13zm2 2h5v4h-5zm7 0h5v4h-5zm-7 5h5v4h-5zm7 0h5v4h-5z"/>
+ <path id="table" d="M4 6v11h15V6zm1 3h6v3H5zm7 0h6v3h-6zm-7 4h6v3H5zm7 0h6v3h-6z"/>
</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
index 66af3753..24e71330 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.png
+++ 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
index 82171db6..aab025e5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-constructive.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"><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"/>
+ <path d="M18.748 11.717c.39.39.39 1.025 0 1.414l-4.95 4.95c-.388.39-1.024.39-1.413 0l-6.01-6.01c-.39-.385-.707-1.153-.707-1.703V6c0-.55.45-1 1-1h4.363c.55 0 1.32.318 1.71.707l6.01 6.01zM8.104 7.457c-.58.575-.578 1.513 0 2.092.577.573 1.515.573 2.094 0 .576-.58.576-1.52 0-2.098-.58-.576-1.518-.577-2.094 0z"/>
</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
index 1de90d48..d8571fe9 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.png
+++ 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
index 3d485128..1fe8f5a6 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-destructive.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"><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"/>
+ <path d="M18.748 11.717c.39.39.39 1.025 0 1.414l-4.95 4.95c-.388.39-1.024.39-1.413 0l-6.01-6.01c-.39-.385-.707-1.153-.707-1.703V6c0-.55.45-1 1-1h4.363c.55 0 1.32.318 1.71.707l6.01 6.01zM8.104 7.457c-.58.575-.578 1.513 0 2.092.577.573 1.515.573 2.094 0 .576-.58.576-1.52 0-2.098-.58-.576-1.518-.577-2.094 0z"/>
</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
index c2334293..1d59c508 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.png
+++ 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
index e5734295..394e4319 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-invert.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"><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"/>
+ <path d="M18.748 11.717c.39.39.39 1.025 0 1.414l-4.95 4.95c-.388.39-1.024.39-1.413 0l-6.01-6.01c-.39-.385-.707-1.153-.707-1.703V6c0-.55.45-1 1-1h4.363c.55 0 1.32.318 1.71.707l6.01 6.01zM8.104 7.457c-.58.575-.578 1.513 0 2.092.577.573 1.515.573 2.094 0 .576-.58.576-1.52 0-2.098-.58-.576-1.518-.577-2.094 0z"/>
</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
index a6759e21..b2c39f70 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.png
+++ 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
index f52e06ce..0f140c3d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-progressive.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"><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"/>
+ <path d="M18.748 11.717c.39.39.39 1.025 0 1.414l-4.95 4.95c-.388.39-1.024.39-1.413 0l-6.01-6.01c-.39-.385-.707-1.153-.707-1.703V6c0-.55.45-1 1-1h4.363c.55 0 1.32.318 1.71.707l6.01 6.01zM8.104 7.457c-.58.575-.578 1.513 0 2.092.577.573 1.515.573 2.094 0 .576-.58.576-1.52 0-2.098-.58-.576-1.518-.577-2.094 0z"/>
</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
index 77fc366a..1049e153 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.png
+++ 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
index 337adb63..ed265981 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag-warning.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"><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"/>
+ <path d="M18.748 11.717c.39.39.39 1.025 0 1.414l-4.95 4.95c-.388.39-1.024.39-1.413 0l-6.01-6.01c-.39-.385-.707-1.153-.707-1.703V6c0-.55.45-1 1-1h4.363c.55 0 1.32.318 1.71.707l6.01 6.01zM8.104 7.457c-.58.575-.578 1.513 0 2.092.577.573 1.515.573 2.094 0 .576-.58.576-1.52 0-2.098-.58-.576-1.518-.577-2.094 0z"/>
</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
index 8e100fcb..3bfbd0b6 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.png
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/tag.svg
index 534824c8..5265e04b 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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">
- <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"/>
+ <path d="M18.748 11.717c.39.39.39 1.025 0 1.414l-4.95 4.95c-.388.39-1.024.39-1.413 0l-6.01-6.01c-.39-.385-.707-1.153-.707-1.703V6c0-.55.45-1 1-1h4.363c.55 0 1.32.318 1.71.707l6.01 6.01zM8.104 7.457c-.58.575-.578 1.513 0 2.092.577.573 1.515.573 2.094 0 .576-.58.576-1.52 0-2.098-.58-.576-1.518-.577-2.094 0z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr-invert.png
new file mode 100644
index 00000000..f5dfa9d4
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr-invert.svg
new file mode 100644
index 00000000..c97070da
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr-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>
+ <path d="M24 6h-4V2h-2v4h-4v2h4v4h2V8h4z"/>
+ </g>
+ <path d="M19 13v7H3c-1.1 0-2-.9-2-2V7h12V6H0v12c0 1.7 1.3 3 3 3h17v-8h-1z"/>
+</svg>
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
index 6b594b29..13b1fc72 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-ltr.svg
@@ -1,7 +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"/>
+ <path d="M24 6h-4V2h-2v4h-4v2h4v4h2V8h4z"/>
</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"/>
+ <path d="M19 13v7H3c-1.1 0-2-.9-2-2V7h12V6H0v12c0 1.7 1.3 3 3 3h17v-8h-1z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl-invert.png
new file mode 100644
index 00000000..23c7292e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl-invert.svg
new file mode 100644
index 00000000..6593fc7a
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl-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="g690">
+ <path d="M0 6h4V2h2v4h4v2H6v4H4V8H0z" id="path692"/>
+ </g>
+ <path d="M5 13v7h16c1.1 0 2-.9 2-2V7H11V6h13v12c0 1.7-1.3 3-3 3H4v-8h1z" id="path694"/>
+</svg>
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
index 36b25a3e..d44c3a41 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/templateAdd-rtl.svg
@@ -1,7 +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"/>
+ <path d="M0 6h4V2h2v4h4v2H6v4H4V8H0z" 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"/>
+ <path d="M5 13v7h16c1.1 0 2-.9 2-2V7H11V6h13v12c0 1.7-1.3 3-3 3H4v-8h1z" id="path694"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright-invert.png
new file mode 100644
index 00000000..fb7b9006
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright-invert.svg
new file mode 100644
index 00000000..ae694bc5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-lefttoright-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="text-dir-ltr">
+ <path d="M7 7H5V6h2l.47.5L8 6h2v1H8v10h2v1H8l-.5-.53L7 18H5v-1h2zm6.976 9v-2H11v-4h2.976V8.044L20 12.022z"/>
+ </g>
+</svg>
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
index 62526a03..7dbff919 100644
--- 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
@@ -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="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"/>
+ <path d="M7 7H5V6h2l.47.5L8 6h2v1H8v10h2v1H8l-.5-.53L7 18H5v-1h2zm6.976 9v-2H11v-4h2.976V8.044L20 12.022z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft-invert.png
new file mode 100644
index 00000000..b935d7c2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft-invert.svg
new file mode 100644
index 00000000..55362855
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-dir-righttoleft-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="text-dir-rtl">
+ <path d="M17 17h2v1h-2l-.47-.5-.53.5h-2v-1h2V7h-2V6h2l.5.53L17 6h2v1h-2zm-6.976-9v2H13v4h-2.976v1.956L4 11.978z"/>
+ </g>
+</svg>
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
index 913bbfd6..76933a62 100644
--- 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
@@ -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="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"/>
+ <path d="M17 17h2v1h-2l-.47-.5-.53.5h-2v-1h2V7h-2V6h2l.5.53L17 6h2v1h-2zm-6.976-9v2H13v4h-2.976v1.956L4 11.978z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style-invert.png
new file mode 100644
index 00000000..4bea5a11
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style-invert.svg
new file mode 100644
index 00000000..0367cfe0
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style-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="text-style">
+ <path id="a" d="M15.296 18h2.79l-1.14-12h-2.79L6 18h2.79l2.038-3h4.183l.29 3zm-3.11-5L14.5 9.6l.323 3.4H12.19z"/>
+ <path id="underline" d="M6 19h12v1H6v-1z"/>
+ </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
index 4484496f..a2f48bea 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.png
+++ 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
index 0198c355..466672eb 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/text-style.svg
@@ -1,7 +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"/>
+ <path id="a" d="M15.296 18h2.79l-1.14-12h-2.79L6 18h2.79l2.038-3h4.183l.29 3zm-3.11-5L14.5 9.6l.323 3.4H12.19z"/>
+ <path id="underline" d="M6 19h12v1H6v-1z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr-invert.png
new file mode 100644
index 00000000..fde9f52b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr-invert.svg
new file mode 100644
index 00000000..30915b74
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-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="M11.1 13.1C9.3 11 8.4 8.8 8.1 8h4.7l.7-2H8V3H6v3H1v2h5c-.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.2L18 6h-3l-4.7 14h2.2zm4-12l2 6h-4l2-6z"/>
+</svg>
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
index 7740e43e..8954a21a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-ltr.svg
@@ -1,4 +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"/>
+ <path d="M11.1 13.1C9.3 11 8.4 8.8 8.1 8h4.7l.7-2H8V3H6v3H1v2h5c-.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.2L18 6h-3l-4.7 14h2.2zm4-12l2 6h-4l2-6z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl-invert.png
new file mode 100644
index 00000000..09ab6312
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl-invert.svg
new file mode 100644
index 00000000..de634a89
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-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="M12.4 13.1c1.8-2.1 2.7-4.3 3-5.1h-4.7L10 6h5.5V3h2v3h5v2h-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.2zM11 20l-1.3-4H4.4l-1.3 4H.9L5.5 6h3l4.7 14H11zM7 8l-2 6h4L7 8z" id="path704"/>
+</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
index 17f543ca..38066d69 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.png
+++ 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
index c78e6222..44ba9719 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/translation-rtl.svg
@@ -1,4 +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"/>
+ <path d="M12.4 13.1c1.8-2.1 2.7-4.3 3-5.1h-4.7L10 6h5.5V3h2v3h5v2h-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.2zM11 20l-1.3-4H4.4l-1.3 4H.9L5.5 6h3l4.7 14H11zM7 8l-2 6h4L7 8z" id="path704"/>
</svg>
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
index baa31f6c..65ba012d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash-invert.svg
@@ -1,4 +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"/>
+ <path d="M6 8c0-1.1.9-2 2-2h2l1-1h2l1 1h2c1.1 0 2 .9 2 2H6zm1 1h10l-1 11H8z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.svg
index f5914312..76502dce 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trash.svg
@@ -1,4 +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"/>
+ <path d="M6 8c0-1.1.9-2 2-2h2l1-1h2l1 1h2c1.1 0 2 .9 2 2H6zm1 1h10l-1 11H8z"/>
</svg>
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
index 20cd2991..8717c944 100644
--- 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
@@ -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"><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"/>
+ <path d="M20.5 20.5L5 5 4 6l3 3 1 11h8l.2-1.8 3.3 3.3zM17 9h-6l5.5 5.5zm1-1c0-1.1-.9-2-2-2h-2l-1-1h-2l-1 1H8l2 2h8z"/>
</g>
</svg>
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
index 0731f056..071bd325 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-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>
- <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"/>
+ <path d="M20.5 20.5L5 5 4 6l3 3 1 11h8l.2-1.8 3.3 3.3zM17 9h-6l5.5 5.5zm1-1c0-1.1-.9-2-2-2h-2l-1-1h-2l-1 1H8l2 2h8z"/>
</g>
</svg>
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
index aebedec7..af43db73 100644
--- 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
@@ -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"><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"/>
+ <path d="M4 20.5L19.5 5l1 1-3 3-1 11h-8l-.2-1.8L5 21.5zM7.5 9h6L8 14.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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.svg
index 2a92cbef..69c17b46 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/trashUndo-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="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"/>
+ <path d="M4 20.5L19.5 5l1 1-3 3-1 11h-8l-.2-1.8L5 21.5zM7.5 9h6L8 14.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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr-destructive.svg
index 97fcdc4c..9629e8f9 100644
--- 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
@@ -1,4 +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"/>
+ <path d="M12 9V7s0-5-4.5-5S3 7 3 7h2s0-3 2.5-3S10 7 10 7v2H7v7c0 1.7 1.3 3 3 3h10V9z" id="path726"/>
</svg>
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
index b496a065..ef4247ab 100644
--- 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
@@ -1,4 +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"/>
+ <path d="M12 9V7s0-5-4.5-5S3 7 3 7h2s0-3 2.5-3S10 7 10 7v2H7v7c0 1.7 1.3 3 3 3h10V9z" id="path726"/>
</svg>
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
index 66c024a9..cf12ece5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-ltr.svg
@@ -1,4 +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"/>
+ <path d="M12 9V7s0-5-4.5-5S3 7 3 7h2s0-3 2.5-3S10 7 10 7v2H7v7c0 1.7 1.3 3 3 3h10V9z" id="path726"/>
</svg>
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
index a52f0fe3..73e0db1c 100644
--- 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
@@ -1,4 +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"/>
+ <path d="M11 9V7s0-5 4.5-5S20 7 20 7h-2s0-3-2.5-3S13 7 13 7v2h3v7c0 1.7-1.3 3-3 3H3V9z" id="path726"/>
</svg>
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
index 814af1dd..ce5f164c 100644
--- 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
@@ -1,4 +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"/>
+ <path d="M11 9V7s0-5 4.5-5S20 7 20 7h-2s0-3-2.5-3S13 7 13 7v2h3v7c0 1.7-1.3 3-3 3H3V9z" id="path726"/>
</svg>
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
index 07cecbfe..00045359 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unLock-rtl.svg
@@ -1,4 +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"/>
+ <path d="M11 9V7s0-5 4.5-5S20 7 20 7h-2s0-3-2.5-3S13 7 13 7v2h3v7c0 1.7-1.3 3-3 3H3V9z" id="path726"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-constructive.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-constructive.png
new file mode 100644
index 00000000..c30fe9d7
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-constructive.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-constructive.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-constructive.svg
new file mode 100644
index 00000000..818f5a71
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/unStar-constructive.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: #00AF89 }</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/underline-a-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a-invert.png
new file mode 100644
index 00000000..b12856d1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a-invert.svg
new file mode 100644
index 00000000..3581c579
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a-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="underline-a">
+ <path id="a" d="M14.424 16H16.5L13.037 6H10.96L7.5 16h2.077l.627-2h3.604l.616 2zm-3.92-3.623L12 7.997l1.51 4.38h-3z"/>
+ <path id="underline" d="M7 17h10v1H7v-1z"/>
+ </g>
+</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
index 81713bdd..f4add0a0 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.png
+++ 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
index dd6dde36..1ddae104 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-a.svg
@@ -1,7 +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"/>
+ <path id="a" d="M14.424 16H16.5L13.037 6H10.96L7.5 16h2.077l.627-2h3.604l.616 2zm-3.92-3.623L12 7.997l1.51 4.38h-3z"/>
+ <path id="underline" d="M7 17h10v1H7v-1z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u-invert.png
new file mode 100644
index 00000000..c1f52df1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u-invert.svg
new file mode 100644
index 00000000..c998822e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u-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="underline-u">
+ <path id="u" d="M8 6h2v5.96c-.104 1.706.695 2 2 2.04 1.777.062 2.002-.88 2-2.04V6h2v6.123c0 1.28-.338 2.245-1.016 2.898-.672.655-1.666.98-2.98.98-1.32 0-2.32-.323-2.996-.98C8.336 14.37 8 13.406 8 12.127V6"/>
+ <path id="underline" d="M7 17h10v1H7v-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
index c4eb2a21..2504e668 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.png
+++ 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
index fbd7c147..f5aaf5d6 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/underline-u.svg
@@ -1,7 +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"/>
+ <path id="u" d="M8 6h2v5.96c-.104 1.706.695 2 2 2.04 1.777.062 2.002-.88 2-2.04V6h2v6.123c0 1.28-.338 2.245-1.016 2.898-.672.655-1.666.98-2.98.98-1.32 0-2.32-.323-2.996-.98C8.336 14.37 8 13.406 8 12.127V6"/>
+ <path id="underline" d="M7 17h10v1H7v-1z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle-invert.png
new file mode 100644
index 00000000..720f335b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle-invert.svg
new file mode 100644
index 00000000..b23189f3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle-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 8l8 10H4z"/>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.svg
index 9e5e72f6..9f0efc59 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upTriangle.svg
@@ -1,4 +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"/>
+ <path d="M12 8l8 10H4z"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr-invert.png
new file mode 100644
index 00000000..c7b7fd58
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr-invert.svg
new file mode 100644
index 00000000..2ba1d09c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-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="M10 13c0 1.7 1.3 3 3 3V9h3l-4.5-5L7 9h3v4zm7 0v5H7c-.6 0-1-.4-1-1v-4H4v4c0 1.9 1.3 3 3 3h12v-7h-2z"/>
+ </g>
+</svg>
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
index 18879e32..e07541d8 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-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>
- <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"/>
+ <path d="M10 13c0 1.7 1.3 3 3 3V9h3l-4.5-5L7 9h3v4zm7 0v5H7c-.6 0-1-.4-1-1v-4H4v4c0 1.9 1.3 3 3 3h12v-7h-2z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl-invert.png
new file mode 100644
index 00000000..1fb09950
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl-invert.svg
new file mode 100644
index 00000000..b181c6c2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-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="g736">
+ <path d="M13 13c0 1.7-1.3 3-3 3V9H7l4.5-5L16 9h-3v4zm-7 0v5h10c.6 0 1-.4 1-1v-4h2v4c0 1.9-1.3 3-3 3H4v-7h2z" id="path738"/>
+ </g>
+</svg>
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
index 7a3535ba..0f3d6297 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/upload-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="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"/>
+ <path d="M13 13c0 1.7-1.3 3-3 3V9H7l4.5-5L16 9h-3v4zm-7 0v5h10c.6 0 1-.4 1-1v-4h2v4c0 1.9-1.3 3-3 3H4v-7h2z" id="path738"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr-invert.png
new file mode 100644
index 00000000..b2347633
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr-invert.svg
new file mode 100644
index 00000000..af68b98b
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-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="M16 5H4v12c0 1.7 1.3 3 3 3h12V8c0-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.2S13.3 9 14 9zM9 9c.7 0 1.2.6 1.2 1.2s-.5 1.3-1.2 1.3-1.2-.6-1.2-1.2S8.3 9 9 9zm7 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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.svg
index 5dcc3179..7f526e52 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-ltr.svg
@@ -1,4 +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"/>
+ <path d="M16 5H4v12c0 1.7 1.3 3 3 3h12V8c0-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.2S13.3 9 14 9zM9 9c.7 0 1.2.6 1.2 1.2s-.5 1.3-1.2 1.3-1.2-.6-1.2-1.2S8.3 9 9 9zm7 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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl-invert.png
new file mode 100644
index 00000000..29d54e22
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl-invert.svg
new file mode 100644
index 00000000..8a8e6ece
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-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="M7 5h12v12c0 1.7-1.3 3-3 3H4V8c0-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.2S9.7 9 9 9zm5 0c-.7 0-1.2.6-1.2 1.2s.5 1.3 1.2 1.3 1.2-.6 1.2-1.2S14.7 9 14 9zm-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/userActive-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.svg
index a5e4dc95..a451f00d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userActive-rtl.svg
@@ -1,4 +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"/>
+ <path d="M7 5h12v12c0 1.7-1.3 3-3 3H4V8c0-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.2S9.7 9 9 9zm5 0c-.7 0-1.2.6-1.2 1.2s.5 1.3 1.2 1.3 1.2-.6 1.2-1.2S14.7 9 14 9zm-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar-invert.png
new file mode 100644
index 00000000..1adbac00
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar-invert.svg
new file mode 100644
index 00000000..22b83ed6
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar-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="g4">
+ <g id="g6">
+ <path d="M11.5 13c1.7 0 3.5-2 3.5-5 0-.1 0-4-3.5-4S8 7.9 8 8c0 3 1.8 5 3.5 5zm3.5-1c-.4.7-1.7 2-3.5 2S8.3 12.7 8 12H6c-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/userAvatar.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.svg
index e9687fa6..1bf7d80c 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userAvatar.svg
@@ -2,7 +2,7 @@
<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"/>
+ <path d="M11.5 13c1.7 0 3.5-2 3.5-5 0-.1 0-4-3.5-4S8 7.9 8 8c0 3 1.8 5 3.5 5zm3.5-1c-.4.7-1.7 2-3.5 2S8.3 12.7 8 12H6c-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr-invert.png
new file mode 100644
index 00000000..184deb73
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr-invert.svg
new file mode 100644
index 00000000..9bfdcd90
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-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="M16 5H4v12c0 1.7 1.3 3 3 3h12V8c0-1.7-1.3-3-3-3zm-9.3 5.4C6.2 10 6 9.6 6 9c.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-.6S12 9.6 12 9c.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-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.png
index 7e4cfd1a..b6f9b159 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.png
+++ 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
index bb5b0968..e58bbc3f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-ltr.svg
@@ -1,4 +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"/>
+ <path d="M16 5H4v12c0 1.7 1.3 3 3 3h12V8c0-1.7-1.3-3-3-3zm-9.3 5.4C6.2 10 6 9.6 6 9c.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-.6S12 9.6 12 9c.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl-invert.png
new file mode 100644
index 00000000..fad58d4d
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl-invert.svg
new file mode 100644
index 00000000..cc568bb2
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-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="M7 5h12v12c0 1.7-1.3 3-3 3H4V8c0-1.7 1.3-3 3-3zm9.3 5.4c.5-.4.7-.8.7-1.4-.6.6-1.5.9-2.5.9S12.6 9.6 12 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.9S6.6 9.6 6 9c0 .6.2 1 .7 1.4z" id="path758"/>
+</svg>
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
index 4a9fd0d7..d4476bdc 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userInactive-rtl.svg
@@ -1,4 +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"/>
+ <path d="M7 5h12v12c0 1.7-1.3 3-3 3H4V8c0-1.7 1.3-3 3-3zm9.3 5.4c.5-.4.7-.8.7-1.4-.6.6-1.5.9-2.5.9S12.6 9.6 12 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.9S6.6 9.6 6 9c0 .6.2 1 .7 1.4z" id="path758"/>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr-invert.png
new file mode 100644
index 00000000..0d2d3047
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr-invert.svg
new file mode 100644
index 00000000..0a165c43
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-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="M5 6v11l-3 3h17c1.7 0 3-1.3 3-3V6H5zm11.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-ltr.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.svg
index f516539c..b58974c0 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-ltr.svg
@@ -1,4 +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"/>
+ <path d="M5 6v11l-3 3h17c1.7 0 3-1.3 3-3V6H5zm11.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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl-invert.png
new file mode 100644
index 00000000..68d92b03
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl-invert.svg
new file mode 100644
index 00000000..3b917122
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-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="M19 6v11l3 3H5c-1.7 0-3-1.3-3-3V6h17zM7.8 8.5c-.7 0-1.2.6-1.2 1.2S7.1 11 7.8 11 9 10.4 9 9.8s-.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.3zM10.5 17c5.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/userTalk-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.svg
index 8963fafc..7ef9ec25 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/userTalk-rtl.svg
@@ -1,4 +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"/>
+ <path d="M19 6v11l3 3H5c-1.7 0-3-1.3-3-3V6h17zM7.8 8.5c-.7 0-1.2.6-1.2 1.2S7.1 11 7.8 11 9 10.4 9 9.8s-.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.3zM10.5 17c5.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/viewDetails-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr-invert.svg
index 14e435db..7c064cca 100644
--- 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
@@ -2,8 +2,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"/>
+ <path d="M10 6h12v1H10zm0 2h9v1h-9zm0 2h4v1h-4z"/>
<circle cx="5.5" cy="16.5" r="2.5"/>
- <path d="M10 14h12v1H10zM10 16h9v1h-9zM10 18h4v1h-4z"/>
+ <path d="M10 14h12v1H10zm0 2h9v1h-9zm0 2h4v1h-4z"/>
</g>
</svg>
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
index 4f5f9b3d..1a5092a3 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/viewDetails-ltr.svg
@@ -2,8 +2,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"/>
+ <path d="M10 6h12v1H10zm0 2h9v1h-9zm0 2h4v1h-4z"/>
<circle cx="5.5" cy="16.5" r="2.5"/>
- <path d="M10 14h12v1H10zM10 16h9v1h-9zM10 18h4v1h-4z"/>
+ <path d="M10 14h12v1H10zm0 2h9v1h-9zm0 2h4v1h-4z"/>
</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
deleted file mode 100644
index 118e4687..00000000
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.png
+++ /dev/null
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
deleted file mode 100644
index ae0d94e2..00000000
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/visionSimulator-invert.svg
+++ /dev/null
@@ -1,4 +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"><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/watchlist-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr-invert.png
new file mode 100644
index 00000000..19b4561e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-ltr-invert.svg
new file mode 100644
index 00000000..5e4a2f3f
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-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="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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl-invert.png
new file mode 100644
index 00000000..48bf3839
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl-invert.svg
new file mode 100644
index 00000000..073ef3d1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-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="g780">
+ <path d="M11 14H6v1h5v-1zm0 3H6v-1h5v1zm0 1H6v1h5v-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/watchlist-rtl.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.svg
index 6bbc2fa2..8bfe43e0 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/watchlist-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="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"/>
+ <path d="M11 14H6v1h5v-1zm0 3H6v-1h5v1zm0 1H6v1h5v-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText-invert.png
new file mode 100644
index 00000000..bdf5238e
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText-invert.svg
new file mode 100644
index 00000000..e050baa3
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText-invert.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"><style>* { fill: #FFFFFF }</style>
+ <g>
+ <path d="M23 5h-4v2h2v10h-2v2h4z"/>
+ </g>
+ <g>
+ <path d="M18 5h-4v2h2v10h-2v2h4z"/>
+ </g>
+ <g>
+ <path d="M2 5h4v2H4v10h2v2H2z"/>
+ </g>
+ <g>
+ <path d="M7 5h4v2H9v10h2v2H7z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.svg
index eebd9b1a..ded0fe1a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikiText.svg
@@ -7,9 +7,9 @@
<path d="M18 5h-4v2h2v10h-2v2h4z"/>
</g>
<g>
- <path d="M2 5h4v2h-2v10h2v2h-4z"/>
+ <path d="M2 5h4v2H4v10h2v2H2z"/>
</g>
<g>
- <path d="M7 5h4v2h-2v10h2v2h-4z"/>
+ <path d="M7 5h4v2H9v10h2v2H7z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr-invert.png
new file mode 100644
index 00000000..917a577c
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr-invert.svg
new file mode 100644
index 00000000..652b9c47
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-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>
+ <path d="M15 9l.7-1.8c.9.4 1.8.7 2.4.9l-.6 1.7v.2L15 9zm-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 .6L1.7 5c.9-.6 1.9-.9 3.1-.9v2zm-4.3.7l1.8.8c-.3.7-.3 1.3-.1 1.8l-1.9.7C0 8.9 0 7.8.5 6.8zm4.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.5S5 18.4 5 16.5 6.6 13 8.5 13s3.5 1.6 3.5 3.5z"/>
+ </g>
+ <path d="M24 8l-1-1-1.5 1.5L20 7l-1 1 1.5 1.5L19 11l1 1 1.5-1.5L23 12l1-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-ltr.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.png
index 41743b3a..db4b6a57 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.png
+++ 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
index c606becd..6dbe1b4e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-ltr.svg
@@ -1,8 +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"/>
+ <path d="M15 9l.7-1.8c.9.4 1.8.7 2.4.9l-.6 1.7v.2L15 9zm-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 .6L1.7 5c.9-.6 1.9-.9 3.1-.9v2zm-4.3.7l1.8.8c-.3.7-.3 1.3-.1 1.8l-1.9.7C0 8.9 0 7.8.5 6.8zm4.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.5S5 18.4 5 16.5 6.6 13 8.5 13s3.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"/>
+ <path d="M24 8l-1-1-1.5 1.5L20 7l-1 1 1.5 1.5L19 11l1 1 1.5-1.5L23 12l1-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-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl-invert.png
new file mode 100644
index 00000000..92afc203
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-rtl-invert.svg
new file mode 100644
index 00000000..285c8cc1
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/wikitrail-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="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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.svg
index 0aeb6168..a1d59d5f 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window-invert.svg
@@ -1,7 +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"/>
+ <path id="title" d="M7 10h10v1H7z"/>
+ <path id="frame" d="M16 19H8c-2.206 0-4-1.794-4-4V9c0-2.206 1.794-4 4-4h8c2.206 0 4 1.794 4 4v6c0 2.206-1.794 4-4 4zM8 7c-1.103 0-2 .897-2 2v6c0 1.103.897 2 2 2h8c1.103 0 2-.897 2-2V9c0-1.103-.897-2-2-2H8z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/icons/window.svg b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window.svg
index cd3b76c2..093c8228 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/icons/window.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/icons/window.svg
@@ -1,7 +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="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"/>
+ <path id="title" d="M7 10h10v1H7z"/>
+ <path id="frame" d="M16 19H8c-2.206 0-4-1.794-4-4V9c0-2.206 1.794-4 4-4h8c2.206 0 4 1.794 4 4v6c0 2.206-1.794 4-4 4zM8 7c-1.103 0-2 .897-2 2v6c0 1.103.897 2 2 2h8c1.103 0 2-.897 2-2V9c0-1.103-.897-2-2-2H8z"/>
</g>
</svg>
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
index cd666495..0d17c02a 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert-invert.svg
@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?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"/>
+ <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 6zM5 7h2V2H5zm0 3h2V8H5z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/alert.svg
index d9dc6a87..868bcc96 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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"?>
+<?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">
- <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"/>
+ <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 6zM5 7h2V2H5zm0 3h2V8H5z"/>
</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
index f18841d4..fcb50d6f 100644
--- 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
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
index 847f9358..7567b5d6 100644
--- 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
@@ -1,8 +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="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>
+<?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="down">
+ <path id="arrow" d="M1 4h10L6 9 1 4"/>
+ </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
index 15ec5861..034fe2b2 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.png
+++ 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
index 17380577..f5c76f37 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-down.svg
@@ -1,8 +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="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>
+<?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">
+ <path id="arrow" d="M1 4h10L6 9 1 4"/>
+ </g>
+</svg>
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
index 2a91c027..63384fa0 100644
--- 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
@@ -1,8 +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="-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>
+<?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="ltr">
+ <path id="arrow" d="M4 1v10l5-5-5-5"/>
+ </g>
+</svg>
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
index fb366e64..059372d5 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-ltr.svg
@@ -1,8 +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="-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>
+<?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">
+ <path id="arrow" d="M4 1v10l5-5-5-5"/>
+ </g>
+</svg>
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
index 3cce872e..a9e9ce31 100644
--- 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
@@ -1,8 +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="-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>
+<?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="rtl">
+ <path id="arrow" d="M8 11V1L3 6l5 5"/>
+ </g>
+</svg>
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
index 62b6bb50..c6498e82 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-rtl.svg
@@ -1,8 +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="-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>
+<?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">
+ <path id="arrow" d="M8 11V1L3 6l5 5"/>
+ </g>
+</svg>
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
index 50da8de0..2d11d4fe 100644
--- 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
@@ -1,8 +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="-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>
+<?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="up">
+ <path id="arrow" d="M1 8h10L6 3 1 8"/>
+ </g>
+</svg>
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
index 20e734fb..5eada07d 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/arrow-up.svg
@@ -1,8 +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="-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>
+<?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">
+ <path id="arrow" d="M1 8h10L6 3 1 8"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear-invert.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear-invert.png
new file mode 100644
index 00000000..d68353bf
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear-invert.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear-invert.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear-invert.svg
new file mode 100644
index 00000000..5b030542
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear-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="clear">
+ <path id="circle-with-cross" d="M6 0C2.7 0 0 2.7 0 6s2.7 6 6 6 6-2.7 6-6-2.7-6-6-6zM3.5 2.5L6 5l2.5-2.5 1 1L7 6l2.5 2.5-1 1L6 7 3.5 9.5l-1-1L5 6 2.5 3.5z"/>
+ </g>
+</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear.png b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear.png
new file mode 100644
index 00000000..5db444c5
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear.png
Binary files differ
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear.svg
new file mode 100644
index 00000000..3c010c10
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/clear.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="clear">
+ <path id="circle-with-cross" d="M6 0C2.7 0 0 2.7 0 6s2.7 6 6 6 6-2.7 6-6-2.7-6-6-6zM3.5 2.5L6 5l2.5-2.5 1 1L7 6l2.5 2.5-1 1L6 7 3.5 9.5l-1-1L5 6 2.5 3.5z"/>
+ </g>
+</svg>
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
index 30baa50c..40686996 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required-invert.svg
@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="UTF-8"?>
+<?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"/>
+ <path d="M5 1h2v10H5zm4.83 1.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.svg b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/required.svg
index 969fa2d8..d1e0cba6 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/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"?>
+<?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">
- <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"/>
+ <path d="M5 1h2v10H5zm4.83 1.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
index 2840bef1..68fcab8d 100644
--- 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
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
index f46b1eeb..cf4de688 100644
--- 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
@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?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="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"/>
+ <path id="path3051" d="M10.37 9.474L7.994 7.1l-.17-.1c.404-.566.644-1.26.644-2.01-.002-1.92-1.56-3.476-3.478-3.476-1.92 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.75 0 1.442-.24 2.01-.647l.098.17 2.375 2.373c.19.188.543.142.79-.105s.293-.6.104-.79zm-5.38-2.27c-1.22 0-2.213-.99-2.213-2.213 0-1.22.99-2.21 2.212-2.21 1.22 0 2.21.99 2.21 2.214s-.99 2.213-2.21 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
index df1c61ed..2718a9b0 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.png
+++ 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
index 266349ed..9b3c1997 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-ltr.svg
@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?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="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"/>
+ <path id="path3051" d="M10.37 9.474L7.994 7.1l-.17-.1c.404-.566.644-1.26.644-2.01-.002-1.92-1.56-3.476-3.478-3.476-1.92 0-3.478 1.557-3.478 3.478 0 1.92 1.557 3.477 3.478 3.477.75 0 1.442-.24 2.01-.647l.098.17 2.375 2.373c.19.188.543.142.79-.105s.293-.6.104-.79zm-5.38-2.27c-1.22 0-2.213-.99-2.213-2.213 0-1.22.99-2.21 2.212-2.21 1.22 0 2.21.99 2.21 2.214s-.99 2.213-2.21 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
index 665a088b..c8ebef4b 100644
--- 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
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
index bd962d93..41fe9bd5 100644
--- 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
@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?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="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"/>
+ <path id="path3051" d="M1.63 9.474L4.006 7.1l.17-.1c-.404-.566-.644-1.26-.644-2.01.002-1.92 1.56-3.476 3.478-3.476 1.92 0 3.478 1.557 3.478 3.478 0 1.92-1.557 3.477-3.478 3.477-.75 0-1.442-.24-2.01-.647l-.098.17-2.375 2.373c-.19.188-.543.142-.79-.105s-.293-.6-.104-.79zm5.378-2.27c1.22 0 2.213-.99 2.213-2.213 0-1.22-.99-2.21-2.21-2.21S4.8 3.77 4.8 4.995 5.79 7.207 7.01 7.207z"/>
</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
index c9443d79..b7a8d221 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.png
+++ 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
index 5368fd7c..3201301e 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/indicators/search-rtl.svg
@@ -1,6 +1,6 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<?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="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"/>
+ <path id="path3051" d="M1.63 9.474L4.006 7.1l.17-.1c-.404-.566-.644-1.26-.644-2.01.002-1.92 1.56-3.476 3.478-3.476 1.92 0 3.478 1.557 3.478 3.478 0 1.92-1.557 3.477-3.478 3.477-.75 0-1.442-.24-2.01-.647l-.098.17-2.375 2.373c-.19.188-.543.142-.79-.105s-.293-.6-.104-.79zm5.378-2.27c1.22 0 2.213-.99 2.213-2.213 0-1.22-.99-2.21-2.21-2.21S4.8 3.77 4.8 4.995 5.79 7.207 7.01 7.207z"/>
</g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.svg b/resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.svg
index 63a0b57c..cadec2a6 100644
--- a/resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.svg
+++ b/resources/lib/oojs-ui/themes/mediawiki/images/textures/transparency.svg
@@ -1,10 +1,7 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0" y="0" width="16" height="16" viewBox="0, 0, 16, 16">
- <g id="transparency">
- <path d="M0,0 L8,0 L8,8 L0,8 z" fill="#CCCCCC"/>
- <path d="M8,8 L16,8 L16,16 L8,16 z" fill="#CCCCCC"/>
- <path d="M8,0 L16,0 L16,8 L8,8 z" fill="#FFFFFF"/>
- <path d="M0,8 L8,8 L8,16 L0,16 z" fill="#FFFFFF"/>
- </g>
+<?xml version="1.0" encoding="utf-8"?>
+<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16">
+ <g id="transparency">
+ <path d="M0 0h8v8H0zm8 8h8v8H8z" fill="#ccc"/>
+ <path d="M8 0h8v8H8zM0 8h8v8H0z" fill="#fff"/>
+ </g>
</svg>
diff --git a/resources/lib/oojs-ui/themes/mediawiki/indicators.json b/resources/lib/oojs-ui/themes/mediawiki/indicators.json
new file mode 100644
index 00000000..5a832585
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/indicators.json
@@ -0,0 +1,30 @@
+{
+ "selectorWithoutVariant": ".oo-ui-indicator-{name}",
+ "selectorWithVariant": ".oo-ui-image-{variant}.oo-ui-indicator-{name}",
+ "intro": "@import '../../../../src/styles/common';",
+ "variants": {
+ "invert": {
+ "color": "#FFFFFF",
+ "global": true
+ }
+ },
+ "images": {
+ "alert": { "file": "images/indicators/alert.svg" },
+ "clear": { "file": "images/indicators/clear.svg" },
+ "up": { "file": "images/indicators/arrow-up.svg" },
+ "down": { "file": "images/indicators/arrow-down.svg" },
+ "next": { "file": {
+ "ltr": "images/indicators/arrow-ltr.svg",
+ "rtl": "images/indicators/arrow-rtl.svg"
+ } },
+ "previous": { "file": {
+ "ltr": "images/indicators/arrow-rtl.svg",
+ "rtl": "images/indicators/arrow-ltr.svg"
+ } },
+ "required": { "file": "images/indicators/required.svg" },
+ "search": { "file": {
+ "ltr": "images/indicators/search-ltr.svg",
+ "rtl": "images/indicators/search-rtl.svg"
+ } }
+ }
+}
diff --git a/resources/lib/oojs-ui/themes/mediawiki/textures.json b/resources/lib/oojs-ui/themes/mediawiki/textures.json
new file mode 100644
index 00000000..e90730ab
--- /dev/null
+++ b/resources/lib/oojs-ui/themes/mediawiki/textures.json
@@ -0,0 +1,8 @@
+{
+ "prefix": "oo-ui-texture",
+ "intro": "@import '../../../../src/styles/common';",
+ "images": {
+ "pending": { "file": "images/textures/pending.gif" },
+ "transparency": { "file": "images/textures/transparency.svg" }
+ }
+}
diff --git a/resources/lib/oojs/oojs.jquery.js b/resources/lib/oojs/oojs.jquery.js
index 18dc5649..9395ecfe 100644
--- a/resources/lib/oojs/oojs.jquery.js
+++ b/resources/lib/oojs/oojs.jquery.js
@@ -1,12 +1,12 @@
/*!
- * OOjs v1.1.6 optimised for jQuery
+ * OOjs v1.1.9 optimised for jQuery
* https://www.mediawiki.org/wiki/OOjs
*
* Copyright 2011-2015 OOjs Team and other contributors.
* Released under the MIT license
* http://oojs.mit-license.org
*
- * Date: 2015-03-19T00:42:55Z
+ * Date: 2015-08-25T21:35:29Z
*/
( function ( global ) {
@@ -22,7 +22,21 @@ var
oo = {},
// Optimisation: Local reference to Object.prototype.hasOwnProperty
hasOwn = oo.hasOwnProperty,
- toString = oo.toString;
+ toString = oo.toString,
+ // Object.create() is impossible to fully polyfill, so don't require it
+ createObject = Object.create || ( function () {
+ // Reusable constructor function
+ function Empty() {}
+ return function ( prototype, properties ) {
+ var obj;
+ Empty.prototype = prototype;
+ obj = new Empty();
+ if ( properties && hasOwn.call( properties, 'constructor' ) ) {
+ obj.constructor = properties.constructor.value;
+ }
+ return obj;
+ };
+ } )();
/* Class Methods */
@@ -88,7 +102,7 @@ oo.inheritClass = function ( targetFn, originFn ) {
// allows people to comply with their style guide.
targetFn['super'] = targetFn.parent = originFn;
- targetFn.prototype = Object.create( originFn.prototype, {
+ targetFn.prototype = createObject( originFn.prototype, {
// Restore constructor property of targetFn
constructor: {
value: targetConstructor,
@@ -100,7 +114,7 @@ oo.inheritClass = function ( targetFn, originFn ) {
// Extend static properties - always initialize both sides
oo.initClass( originFn );
- targetFn.static = Object.create( originFn.static );
+ targetFn.static = createObject( originFn.static );
};
/**
@@ -108,12 +122,12 @@ oo.inheritClass = function ( targetFn, originFn ) {
*
* The 'constructor' (whether implicit or explicit) is not copied over.
*
- * This does not create inheritance to the origin. If inheritance is needed
- * use oo.inheritClass instead.
+ * This does not create inheritance to the origin. If you need inheritance,
+ * use OO.inheritClass instead.
*
* Beware: This can redefine a prototype property, call before setting your prototypes.
*
- * Beware: Don't call before oo.inheritClass.
+ * Beware: Don't call before OO.inheritClass.
*
* function Foo() {}
* function Context() {}
@@ -242,7 +256,7 @@ oo.setProp = function ( obj ) {
oo.cloneObject = function ( origin ) {
var key, r;
- r = Object.create( origin.constructor.prototype );
+ r = createObject( origin.constructor.prototype );
for ( key in origin ) {
if ( hasOwn.call( origin, key ) ) {
@@ -698,12 +712,9 @@ oo.isPlainObject = $.isPlainObject;
/**
* Emit an event.
*
- * TODO: Should this be chainable? What is the usefulness of the boolean
- * return value here?
- *
* @param {string} event Type of event
* @param {Mixed} args First in a list of variadic arguments passed to event handler (optional)
- * @return {boolean} If event was handled by at least one listener
+ * @return {boolean} Whether the event was handled by at least one listener
*/
oo.EventEmitter.prototype.emit = function ( event ) {
var args = [],
@@ -826,12 +837,18 @@ oo.mixinClass( oo.Registry, oo.EventEmitter );
* @param {Mixed} data
*/
+/**
+ * @event unregister
+ * @param {string} name
+ * @param {Mixed} data Data removed from registry
+ */
+
/* Methods */
/**
* Associate one or more symbolic names with some data.
*
- * Only the base name will be registered, overriding any existing entry with the same base name.
+ * Any existing entry with the same name will be overridden.
*
* @param {string|string[]} name Symbolic name or list of symbolic names
* @param {Mixed} data Data to associate with symbolic name
@@ -853,9 +870,31 @@ oo.Registry.prototype.register = function ( name, data ) {
};
/**
- * Get data for a given symbolic name.
+ * Remove one or more symbolic names from the registry
*
- * Lookups are done using the base name.
+ * @param {string|string[]} name Symbolic name or list of symbolic names
+ * @fires unregister
+ * @throws {Error} Name argument must be a string or array
+ */
+oo.Registry.prototype.unregister = function ( name ) {
+ var i, len, data;
+ if ( typeof name === 'string' ) {
+ data = this.lookup( name );
+ if ( data !== undefined ) {
+ delete this.registry[name];
+ this.emit( 'unregister', name, data );
+ }
+ } else if ( Array.isArray( name ) ) {
+ for ( i = 0, len = name.length; i < len; i++ ) {
+ this.unregister( name[i] );
+ }
+ } else {
+ throw new Error( 'Name must be a string or array, cannot be a ' + typeof name );
+ }
+};
+
+/**
+ * Get data for a given symbolic name.
*
* @param {string} name Symbolic name
* @return {Mixed|undefined} Data associated with symbolic name
@@ -866,6 +905,8 @@ oo.Registry.prototype.lookup = function ( name ) {
}
};
+/*global createObject */
+
/**
* @class OO.Factory
* @extends OO.Registry
@@ -873,10 +914,8 @@ oo.Registry.prototype.lookup = function ( name ) {
* @constructor
*/
oo.Factory = function OoFactory() {
+ // Parent constructor
oo.Factory.parent.call( this );
-
- // Properties
- this.entries = [];
};
/* Inheritance */
@@ -911,12 +950,34 @@ oo.Factory.prototype.register = function ( constructor ) {
if ( typeof name !== 'string' || name === '' ) {
throw new Error( 'Name must be a string and must not be empty' );
}
- this.entries.push( name );
+ // Parent method
oo.Factory.parent.prototype.register.call( this, name, constructor );
};
/**
+ * Unregister a constructor from the factory.
+ *
+ * @param {Function} constructor Constructor to unregister
+ * @throws {Error} Name must be a string and must not be empty
+ * @throws {Error} Constructor must be a function
+ */
+oo.Factory.prototype.unregister = function ( constructor ) {
+ var name;
+
+ if ( typeof constructor !== 'function' ) {
+ throw new Error( 'constructor must be a function, cannot be a ' + typeof constructor );
+ }
+ name = constructor.static && constructor.static.name;
+ if ( typeof name !== 'string' || name === '' ) {
+ throw new Error( 'Name must be a string and must not be empty' );
+ }
+
+ // Parent method
+ oo.Factory.parent.prototype.unregister.call( this, name );
+};
+
+/**
* Create an object based on a name.
*
* Name is used to look up the constructor to use, while all additional arguments are passed to the
@@ -946,7 +1007,7 @@ oo.Factory.prototype.create = function ( name ) {
// the constructor's prototype (which also makes it an "instanceof" the constructor),
// then invoke the constructor with the object as context, and return it (ignoring
// the constructor's return value).
- obj = Object.create( constructor.prototype );
+ obj = createObject( constructor.prototype );
constructor.apply( obj, args );
return obj;
};
diff --git a/resources/lib/phpjs-sha1/LICENSE.txt b/resources/lib/phpjs-sha1/LICENSE.txt
new file mode 100644
index 00000000..04caf536
--- /dev/null
+++ b/resources/lib/phpjs-sha1/LICENSE.txt
@@ -0,0 +1,20 @@
+Copyright (c) 2013 Kevin van Zonneveld (http://kvz.io)
+and Contributors (http://phpjs.org/authors)
+
+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/phpjs-sha1/sha1.js b/resources/lib/phpjs-sha1/sha1.js
new file mode 100644
index 00000000..93c533d7
--- /dev/null
+++ b/resources/lib/phpjs-sha1/sha1.js
@@ -0,0 +1,147 @@
+function sha1(str) {
+ // discuss at: http://phpjs.org/functions/sha1/
+ // original by: Webtoolkit.info (http://www.webtoolkit.info/)
+ // improved by: Michael White (http://getsprink.com)
+ // improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
+ // input by: Brett Zamir (http://brett-zamir.me)
+ // example 1: sha1('Kevin van Zonneveld');
+ // returns 1: '54916d2e62f65b3afa6e192e6a601cdbe5cb5897'
+
+ var rotate_left = function (n, s) {
+ var t4 = (n << s) | (n >>> (32 - s));
+ return t4;
+ };
+
+ /*var lsb_hex = function (val) {
+ // Not in use; needed?
+ var str="";
+ var i;
+ var vh;
+ var vl;
+
+ for ( i=0; i<=6; i+=2 ) {
+ vh = (val>>>(i*4+4))&0x0f;
+ vl = (val>>>(i*4))&0x0f;
+ str += vh.toString(16) + vl.toString(16);
+ }
+ return str;
+ };*/
+
+ var cvt_hex = function (val) {
+ var str = '';
+ var i;
+ var v;
+
+ for (i = 7; i >= 0; i--) {
+ v = (val >>> (i * 4)) & 0x0f;
+ str += v.toString(16);
+ }
+ return str;
+ };
+
+ var blockstart;
+ var i, j;
+ var W = new Array(80);
+ var H0 = 0x67452301;
+ var H1 = 0xEFCDAB89;
+ var H2 = 0x98BADCFE;
+ var H3 = 0x10325476;
+ var H4 = 0xC3D2E1F0;
+ var A, B, C, D, E;
+ var temp;
+
+ // utf8_encode
+ str = unescape(encodeURIComponent(str));
+ var str_len = str.length;
+
+ var word_array = [];
+ for (i = 0; i < str_len - 3; i += 4) {
+ j = str.charCodeAt(i) << 24 | str.charCodeAt(i + 1) << 16 | str.charCodeAt(i + 2) << 8 | str.charCodeAt(i + 3);
+ word_array.push(j);
+ }
+
+ switch (str_len % 4) {
+ case 0:
+ i = 0x080000000;
+ break;
+ case 1:
+ i = str.charCodeAt(str_len - 1) << 24 | 0x0800000;
+ break;
+ case 2:
+ i = str.charCodeAt(str_len - 2) << 24 | str.charCodeAt(str_len - 1) << 16 | 0x08000;
+ break;
+ case 3:
+ i = str.charCodeAt(str_len - 3) << 24 | str.charCodeAt(str_len - 2) << 16 | str.charCodeAt(str_len - 1) <<
+ 8 | 0x80;
+ break;
+ }
+
+ word_array.push(i);
+
+ while ((word_array.length % 16) != 14) {
+ word_array.push(0);
+ }
+
+ word_array.push(str_len >>> 29);
+ word_array.push((str_len << 3) & 0x0ffffffff);
+
+ for (blockstart = 0; blockstart < word_array.length; blockstart += 16) {
+ for (i = 0; i < 16; i++) {
+ W[i] = word_array[blockstart + i];
+ }
+ for (i = 16; i <= 79; i++) {
+ W[i] = rotate_left(W[i - 3] ^ W[i - 8] ^ W[i - 14] ^ W[i - 16], 1);
+ }
+
+ A = H0;
+ B = H1;
+ C = H2;
+ D = H3;
+ E = H4;
+
+ for (i = 0; i <= 19; i++) {
+ temp = (rotate_left(A, 5) + ((B & C) | (~B & D)) + E + W[i] + 0x5A827999) & 0x0ffffffff;
+ E = D;
+ D = C;
+ C = rotate_left(B, 30);
+ B = A;
+ A = temp;
+ }
+
+ for (i = 20; i <= 39; i++) {
+ temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0x6ED9EBA1) & 0x0ffffffff;
+ E = D;
+ D = C;
+ C = rotate_left(B, 30);
+ B = A;
+ A = temp;
+ }
+
+ for (i = 40; i <= 59; i++) {
+ temp = (rotate_left(A, 5) + ((B & C) | (B & D) | (C & D)) + E + W[i] + 0x8F1BBCDC) & 0x0ffffffff;
+ E = D;
+ D = C;
+ C = rotate_left(B, 30);
+ B = A;
+ A = temp;
+ }
+
+ for (i = 60; i <= 79; i++) {
+ temp = (rotate_left(A, 5) + (B ^ C ^ D) + E + W[i] + 0xCA62C1D6) & 0x0ffffffff;
+ E = D;
+ D = C;
+ C = rotate_left(B, 30);
+ B = A;
+ A = temp;
+ }
+
+ H0 = (H0 + A) & 0x0ffffffff;
+ H1 = (H1 + B) & 0x0ffffffff;
+ H2 = (H2 + C) & 0x0ffffffff;
+ H3 = (H3 + D) & 0x0ffffffff;
+ H4 = (H4 + E) & 0x0ffffffff;
+ }
+
+ temp = cvt_hex(H0) + cvt_hex(H1) + cvt_hex(H2) + cvt_hex(H3) + cvt_hex(H4);
+ return temp.toLowerCase();
+}
diff --git a/resources/lib/qunitjs/qunit.css b/resources/lib/qunitjs/qunit.css
index 0eb0b017..f1dcd4e1 100644
--- a/resources/lib/qunitjs/qunit.css
+++ b/resources/lib/qunitjs/qunit.css
@@ -1,12 +1,12 @@
/*!
- * QUnit 1.17.1
+ * QUnit 1.18.0
* http://qunitjs.com/
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2015-01-20T19:39Z
+ * Date: 2015-04-03T10:23Z
*/
/** Font Family and Sizes */
@@ -116,7 +116,13 @@
#qunit-tests.hidepass li.running,
#qunit-tests.hidepass li.pass {
- display: none;
+ visibility: hidden;
+ position: absolute;
+ width: 0px;
+ height: 0px;
+ padding: 0;
+ border: 0;
+ margin: 0;
}
#qunit-tests li strong {
@@ -132,6 +138,11 @@
color: #C2CCD1;
text-decoration: none;
}
+
+#qunit-tests li p a {
+ padding: 0.25em;
+ color: #6B6464;
+}
#qunit-tests li a:hover,
#qunit-tests li a:focus {
color: #000;
diff --git a/resources/lib/qunitjs/qunit.js b/resources/lib/qunitjs/qunit.js
index 006ca474..f3542ca9 100644
--- a/resources/lib/qunitjs/qunit.js
+++ b/resources/lib/qunitjs/qunit.js
@@ -1,12 +1,12 @@
/*!
- * QUnit 1.17.1
+ * QUnit 1.18.0
* http://qunitjs.com/
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license
* http://jquery.org/license
*
- * Date: 2015-01-20T19:39Z
+ * Date: 2015-04-03T10:23Z
*/
(function( window ) {
@@ -116,6 +116,9 @@ config = {
// when enabled, all tests must call expect()
requireExpects: false,
+ // depth up-to which object will be dumped
+ maxDepth: 5,
+
// add checkboxes that are persisted in the query-string
// when enabled, the id is set to `true` as a `QUnit.config` property
urlConfig: [
@@ -185,11 +188,17 @@ config.modules.push( config.currentModule );
// String search anywhere in moduleName+testName
config.filter = urlParams.filter;
+ if ( urlParams.maxDepth ) {
+ config.maxDepth = parseInt( urlParams.maxDepth, 10 ) === -1 ?
+ Number.POSITIVE_INFINITY :
+ urlParams.maxDepth;
+ }
+
config.testId = [];
if ( urlParams.testId ) {
// Ensure that urlParams.testId is an array
- urlParams.testId = [].concat( urlParams.testId );
+ urlParams.testId = decodeURIComponent( urlParams.testId ).split( "," );
for ( i = 0; i < urlParams.testId.length; i++ ) {
config.testId.push( urlParams.testId[ i ] );
}
@@ -197,6 +206,9 @@ config.modules.push( config.currentModule );
// Figure out if we're running the tests from a server or not
QUnit.isLocal = location.protocol === "file:";
+
+ // Expose the current QUnit version
+ QUnit.version = "1.18.0";
}());
// Root QUnit object.
@@ -484,20 +496,14 @@ function done() {
});
}
-// Doesn't support IE6 to IE9
+// Doesn't support IE6 to IE9, it will return undefined on these browsers
// 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
+ if ( e.stack ) {
stack = e.stack.split( "\n" );
if ( /^error$/i.test( stack[ 0 ] ) ) {
stack.shift();
@@ -515,9 +521,10 @@ function extractStacktrace( e, offset ) {
}
}
return stack[ offset ];
+
+ // Support: Safari <=6 only
} else if ( e.sourceURL ) {
- // Safari < 6
// exclude useless self-reference for generated Error objects
if ( /qunit.js$/.test( e.sourceURL ) ) {
return;
@@ -529,16 +536,19 @@ function extractStacktrace( e, offset ) {
}
function sourceFromStacktrace( offset ) {
- var e = new Error();
- if ( !e.stack ) {
+ var error = new Error();
+
+ // Support: Safari <=7 only, IE <=10 - 11 only
+ // Not all browsers generate the `stack` property for `new Error()`, see also #636
+ if ( !error.stack ) {
try {
- throw e;
+ throw error;
} catch ( err ) {
- // This should already be true in most browsers
- e = err;
+ error = err;
}
}
- return extractStacktrace( e, offset );
+
+ return extractStacktrace( error, offset );
}
function synchronize( callback, last ) {
@@ -1123,7 +1133,7 @@ Test.prototype = {
valid: function() {
var include,
- filter = config.filter,
+ filter = config.filter && config.filter.toLowerCase(),
module = QUnit.urlParams.module && QUnit.urlParams.module.toLowerCase(),
fullName = ( this.module.name + ": " + this.testName ).toLowerCase();
@@ -1146,7 +1156,7 @@ Test.prototype = {
include = filter.charAt( 0 ) !== "!";
if ( !include ) {
- filter = filter.toLowerCase().slice( 1 );
+ filter = filter.slice( 1 );
}
// If the filter matches, we need to honour include
@@ -1284,87 +1294,52 @@ QUnit.assert = Assert.prototype = {
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" );
- */
+ notOk: function( result, message ) {
+ message = message || ( !result ? "okay" : "failed, expected argument to be falsy, was: " +
+ QUnit.dump.parse( result ) );
+ this.push( !result, result, false, message );
+ },
+
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 );
},
@@ -1372,7 +1347,8 @@ QUnit.assert = Assert.prototype = {
"throws": function( block, expected, message ) {
var actual, expectedType,
expectedOutput = expected,
- ok = false;
+ ok = false,
+ currentTest = ( this instanceof Assert && this.test ) || QUnit.config.current;
// 'expected' is optional unless doing string comparison
if ( message == null && typeof expected === "string" ) {
@@ -1380,13 +1356,13 @@ QUnit.assert = Assert.prototype = {
expected = null;
}
- this.test.ignoreGlobalErrors = true;
+ currentTest.ignoreGlobalErrors = true;
try {
- block.call( this.test.testEnvironment );
+ block.call( currentTest.testEnvironment );
} catch (e) {
actual = e;
}
- this.test.ignoreGlobalErrors = false;
+ currentTest.ignoreGlobalErrors = false;
if ( actual ) {
expectedType = QUnit.objectType( expected );
@@ -1419,11 +1395,9 @@ QUnit.assert = Assert.prototype = {
expectedOutput = null;
ok = true;
}
-
- this.push( ok, actual, expectedOutput, message );
- } else {
- this.test.pushFailure( message, null, "No exception was thrown." );
}
+
+ currentTest.assert.push( ok, actual, expectedOutput, message );
}
};
@@ -1783,7 +1757,7 @@ QUnit.dump = (function() {
join: join,
//
depth: 1,
- maxDepth: 5,
+ maxDepth: QUnit.config.maxDepth,
// This is the list of parsers, to modify them, use dump.setParser
parsers: {
@@ -1830,7 +1804,7 @@ QUnit.dump = (function() {
nonEnumerableProperties = [ "message", "name" ];
for ( i in nonEnumerableProperties ) {
key = nonEnumerableProperties[ i ];
- if ( key in map && !( key in keys ) ) {
+ if ( key in map && inArray( key, keys ) < 0 ) {
keys.push( key );
}
}
@@ -1949,6 +1923,7 @@ if ( typeof window !== "undefined" ) {
"start",
"stop",
"ok",
+ "notOk",
"equal",
"notEqual",
"propEqual",
@@ -1981,6 +1956,13 @@ if ( typeof exports !== "undefined" && exports ) {
exports.QUnit = QUnit;
}
+if ( typeof define === "function" && define.amd ) {
+ define( function() {
+ return QUnit;
+ } );
+ QUnit.config.autostart = false;
+}
+
// Get a reference to the global object, like window in browsers
}( (function() {
return this;
@@ -1989,150 +1971,1088 @@ if ( typeof exports !== "undefined" && exports ) {
/*istanbul ignore next */
// jscs:disable maximumLineLength
/*
- * Javascript Diff Algorithm
- * By John Resig (http://ejohn.org/)
- * Modified by Chu Alan "sprite"
+ * This file is a modified version of google-diff-match-patch's JavaScript implementation
+ * (https://code.google.com/p/google-diff-match-patch/source/browse/trunk/javascript/diff_match_patch_uncompressed.js),
+ * modifications are licensed as more fully set forth in LICENSE.txt.
+ *
+ * The original source of google-diff-match-patch is attributable and licensed as follows:
*
- * Released under the MIT license.
+ * Copyright 2006 Google Inc.
+ * http://code.google.com/p/google-diff-match-patch/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
* More Info:
- * http://ejohn.org/projects/javascript-diff-algorithm/
+ * https://code.google.com/p/google-diff-match-patch/
*
* 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( "the quick brown fox jumped over", "the quick fox jumps over" ) === "the quick <del>brown </del> fox jump<ins>s</ins><del>ed</del 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;
- };
+ function DiffMatchPatch() {
+
+ // Defaults.
+ // Redefine these in your program to override the defaults.
+
+ // Number of seconds to map a diff before giving up (0 for infinity).
+ this.DiffTimeout = 1.0;
+ // Cost of an empty edit operation in terms of edit characters.
+ this.DiffEditCost = 4;
+ }
+
+ // DIFF FUNCTIONS
+
+ /**
+ * The data structure representing a diff is an array of tuples:
+ * [[DIFF_DELETE, 'Hello'], [DIFF_INSERT, 'Goodbye'], [DIFF_EQUAL, ' world.']]
+ * which means: delete 'Hello', add 'Goodbye' and keep ' world.'
+ */
+ var DIFF_DELETE = -1,
+ DIFF_INSERT = 1,
+ DIFF_EQUAL = 0;
+
+ /**
+ * Find the differences between two texts. Simplifies the problem by stripping
+ * any common prefix or suffix off the texts before diffing.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {boolean=} optChecklines Optional speedup flag. If present and false,
+ * then don't run a line-level diff first to identify the changed areas.
+ * Defaults to true, which does a faster, slightly less optimal diff.
+ * @param {number} optDeadline Optional time when the diff should be complete
+ * by. Used internally for recursive calls. Users should set DiffTimeout
+ * instead.
+ * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
+ */
+ DiffMatchPatch.prototype.DiffMain = function( text1, text2, optChecklines, optDeadline ) {
+ var deadline, checklines, commonlength,
+ commonprefix, commonsuffix, diffs;
+ // Set a deadline by which time the diff must be complete.
+ if ( typeof optDeadline === "undefined" ) {
+ if ( this.DiffTimeout <= 0 ) {
+ optDeadline = Number.MAX_VALUE;
+ } else {
+ optDeadline = ( new Date() ).getTime() + this.DiffTimeout * 1000;
+ }
+ }
+ deadline = optDeadline;
+
+ // Check for null inputs.
+ if ( text1 === null || text2 === null ) {
+ throw new Error( "Null input. (DiffMain)" );
+ }
+
+ // Check for equality (speedup).
+ if ( text1 === text2 ) {
+ if ( text1 ) {
+ return [
+ [ DIFF_EQUAL, text1 ]
+ ];
+ }
+ return [];
+ }
+
+ if ( typeof optChecklines === "undefined" ) {
+ optChecklines = true;
+ }
+
+ checklines = optChecklines;
+
+ // Trim off common prefix (speedup).
+ commonlength = this.diffCommonPrefix( text1, text2 );
+ commonprefix = text1.substring( 0, commonlength );
+ text1 = text1.substring( commonlength );
+ text2 = text2.substring( commonlength );
+
+ // Trim off common suffix (speedup).
+ /////////
+ commonlength = this.diffCommonSuffix( text1, text2 );
+ commonsuffix = text1.substring( text1.length - commonlength );
+ text1 = text1.substring( 0, text1.length - commonlength );
+ text2 = text2.substring( 0, text2.length - commonlength );
+
+ // Compute the diff on the middle block.
+ diffs = this.diffCompute( text1, text2, checklines, deadline );
+
+ // Restore the prefix and suffix.
+ if ( commonprefix ) {
+ diffs.unshift( [ DIFF_EQUAL, commonprefix ] );
+ }
+ if ( commonsuffix ) {
+ diffs.push( [ DIFF_EQUAL, commonsuffix ] );
+ }
+ this.diffCleanupMerge( diffs );
+ return diffs;
+ };
+
+ /**
+ * Reduce the number of edits by eliminating operationally trivial equalities.
+ * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
+ */
+ DiffMatchPatch.prototype.diffCleanupEfficiency = function( diffs ) {
+ var changes, equalities, equalitiesLength, lastequality,
+ pointer, preIns, preDel, postIns, postDel;
+ changes = false;
+ equalities = []; // Stack of indices where equalities are found.
+ equalitiesLength = 0; // Keeping our own length var is faster in JS.
+ /** @type {?string} */
+ lastequality = null;
+ // Always equal to diffs[equalities[equalitiesLength - 1]][1]
+ pointer = 0; // Index of current position.
+ // Is there an insertion operation before the last equality.
+ preIns = false;
+ // Is there a deletion operation before the last equality.
+ preDel = false;
+ // Is there an insertion operation after the last equality.
+ postIns = false;
+ // Is there a deletion operation after the last equality.
+ postDel = false;
+ while ( pointer < diffs.length ) {
+ if ( diffs[ pointer ][ 0 ] === DIFF_EQUAL ) { // Equality found.
+ if ( diffs[ pointer ][ 1 ].length < this.DiffEditCost && ( postIns || postDel ) ) {
+ // Candidate found.
+ equalities[ equalitiesLength++ ] = pointer;
+ preIns = postIns;
+ preDel = postDel;
+ lastequality = diffs[ pointer ][ 1 ];
+ } else {
+ // Not a candidate, and can never become one.
+ equalitiesLength = 0;
+ lastequality = null;
+ }
+ postIns = postDel = false;
+ } else { // An insertion or deletion.
+ if ( diffs[ pointer ][ 0 ] === DIFF_DELETE ) {
+ postDel = true;
+ } else {
+ postIns = true;
+ }
+ /*
+ * Five types to be split:
+ * <ins>A</ins><del>B</del>XY<ins>C</ins><del>D</del>
+ * <ins>A</ins>X<ins>C</ins><del>D</del>
+ * <ins>A</ins><del>B</del>X<ins>C</ins>
+ * <ins>A</del>X<ins>C</ins><del>D</del>
+ * <ins>A</ins><del>B</del>X<del>C</del>
+ */
+ if ( lastequality && ( ( preIns && preDel && postIns && postDel ) ||
+ ( ( lastequality.length < this.DiffEditCost / 2 ) &&
+ ( preIns + preDel + postIns + postDel ) === 3 ) ) ) {
+ // Duplicate record.
+ diffs.splice( equalities[equalitiesLength - 1], 0, [ DIFF_DELETE, lastequality ] );
+ // Change second copy to insert.
+ diffs[ equalities[ equalitiesLength - 1 ] + 1 ][ 0 ] = DIFF_INSERT;
+ equalitiesLength--; // Throw away the equality we just deleted;
+ lastequality = null;
+ if (preIns && preDel) {
+ // No changes made which could affect previous entry, keep going.
+ postIns = postDel = true;
+ equalitiesLength = 0;
+ } else {
+ equalitiesLength--; // Throw away the previous equality.
+ pointer = equalitiesLength > 0 ? equalities[ equalitiesLength - 1 ] : -1;
+ postIns = postDel = false;
+ }
+ changes = true;
+ }
+ }
+ pointer++;
+ }
+
+ if ( changes ) {
+ this.diffCleanupMerge( diffs );
+ }
+ };
+
+ /**
+ * Convert a diff array into a pretty HTML report.
+ * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
+ * @param {integer} string to be beautified.
+ * @return {string} HTML representation.
+ */
+ DiffMatchPatch.prototype.diffPrettyHtml = function( diffs ) {
+ var op, data, x, html = [];
+ for ( x = 0; x < diffs.length; x++ ) {
+ op = diffs[x][0]; // Operation (insert, delete, equal)
+ data = diffs[x][1]; // Text of change.
+ switch ( op ) {
+ case DIFF_INSERT:
+ html[x] = "<ins>" + data + "</ins>";
+ break;
+ case DIFF_DELETE:
+ html[x] = "<del>" + data + "</del>";
+ break;
+ case DIFF_EQUAL:
+ html[x] = "<span>" + data + "</span>";
+ break;
+ }
+ }
+ return html.join("");
+ };
+
+ /**
+ * Determine the common prefix of two strings.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the start of each
+ * string.
+ */
+ DiffMatchPatch.prototype.diffCommonPrefix = function( text1, text2 ) {
+ var pointermid, pointermax, pointermin, pointerstart;
+ // Quick check for common null cases.
+ if ( !text1 || !text2 || text1.charAt(0) !== text2.charAt(0) ) {
+ return 0;
+ }
+ // Binary search.
+ // Performance analysis: http://neil.fraser.name/news/2007/10/09/
+ pointermin = 0;
+ pointermax = Math.min( text1.length, text2.length );
+ pointermid = pointermax;
+ pointerstart = 0;
+ while ( pointermin < pointermid ) {
+ if ( text1.substring( pointerstart, pointermid ) === text2.substring( pointerstart, pointermid ) ) {
+ pointermin = pointermid;
+ pointerstart = pointermin;
+ } else {
+ pointermax = pointermid;
+ }
+ pointermid = Math.floor( ( pointermax - pointermin ) / 2 + pointermin );
+ }
+ return pointermid;
+ };
+
+ /**
+ * Determine the common suffix of two strings.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the end of each string.
+ */
+ DiffMatchPatch.prototype.diffCommonSuffix = function( text1, text2 ) {
+ var pointermid, pointermax, pointermin, pointerend;
+ // Quick check for common null cases.
+ if (!text1 || !text2 || text1.charAt(text1.length - 1) !== text2.charAt(text2.length - 1)) {
+ return 0;
+ }
+ // Binary search.
+ // Performance analysis: http://neil.fraser.name/news/2007/10/09/
+ pointermin = 0;
+ pointermax = Math.min(text1.length, text2.length);
+ pointermid = pointermax;
+ pointerend = 0;
+ while ( pointermin < pointermid ) {
+ if (text1.substring( text1.length - pointermid, text1.length - pointerend ) ===
+ text2.substring( text2.length - pointermid, text2.length - pointerend ) ) {
+ pointermin = pointermid;
+ pointerend = pointermin;
+ } else {
+ pointermax = pointermid;
+ }
+ pointermid = Math.floor( ( pointermax - pointermin ) / 2 + pointermin );
+ }
+ return pointermid;
+ };
+
+ /**
+ * Find the differences between two texts. Assumes that the texts do not
+ * have any common prefix or suffix.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {boolean} checklines Speedup flag. If false, then don't run a
+ * line-level diff first to identify the changed areas.
+ * If true, then run a faster, slightly less optimal diff.
+ * @param {number} deadline Time when the diff should be complete by.
+ * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffCompute = function( text1, text2, checklines, deadline ) {
+ var diffs, longtext, shorttext, i, hm,
+ text1A, text2A, text1B, text2B,
+ midCommon, diffsA, diffsB;
+
+ if ( !text1 ) {
+ // Just add some text (speedup).
+ return [
+ [ DIFF_INSERT, text2 ]
+ ];
+ }
+
+ if (!text2) {
+ // Just delete some text (speedup).
+ return [
+ [ DIFF_DELETE, text1 ]
+ ];
+ }
+
+ longtext = text1.length > text2.length ? text1 : text2;
+ shorttext = text1.length > text2.length ? text2 : text1;
+ i = longtext.indexOf( shorttext );
+ if ( i !== -1 ) {
+ // Shorter text is inside the longer text (speedup).
+ diffs = [
+ [ DIFF_INSERT, longtext.substring( 0, i ) ],
+ [ DIFF_EQUAL, shorttext ],
+ [ DIFF_INSERT, longtext.substring( i + shorttext.length ) ]
+ ];
+ // Swap insertions for deletions if diff is reversed.
+ if ( text1.length > text2.length ) {
+ diffs[0][0] = diffs[2][0] = DIFF_DELETE;
+ }
+ return diffs;
+ }
+
+ if ( shorttext.length === 1 ) {
+ // Single character string.
+ // After the previous speedup, the character can't be an equality.
+ return [
+ [ DIFF_DELETE, text1 ],
+ [ DIFF_INSERT, text2 ]
+ ];
+ }
+
+ // Check to see if the problem can be split in two.
+ hm = this.diffHalfMatch(text1, text2);
+ if (hm) {
+ // A half-match was found, sort out the return data.
+ text1A = hm[0];
+ text1B = hm[1];
+ text2A = hm[2];
+ text2B = hm[3];
+ midCommon = hm[4];
+ // Send both pairs off for separate processing.
+ diffsA = this.DiffMain(text1A, text2A, checklines, deadline);
+ diffsB = this.DiffMain(text1B, text2B, checklines, deadline);
+ // Merge the results.
+ return diffsA.concat([
+ [ DIFF_EQUAL, midCommon ]
+ ], diffsB);
+ }
+
+ if (checklines && text1.length > 100 && text2.length > 100) {
+ return this.diffLineMode(text1, text2, deadline);
+ }
+
+ return this.diffBisect(text1, text2, deadline);
+ };
+
+ /**
+ * Do the two texts share a substring which is at least half the length of the
+ * longer text?
+ * This speedup can produce non-minimal diffs.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {Array.<string>} Five element Array, containing the prefix of
+ * text1, the suffix of text1, the prefix of text2, the suffix of
+ * text2 and the common middle. Or null if there was no match.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffHalfMatch = function(text1, text2) {
+ var longtext, shorttext, dmp,
+ text1A, text2B, text2A, text1B, midCommon,
+ hm1, hm2, hm;
+ if (this.DiffTimeout <= 0) {
+ // Don't risk returning a non-optimal diff if we have unlimited time.
+ return null;
+ }
+ longtext = text1.length > text2.length ? text1 : text2;
+ shorttext = text1.length > text2.length ? text2 : text1;
+ if (longtext.length < 4 || shorttext.length * 2 < longtext.length) {
+ return null; // Pointless.
+ }
+ dmp = this; // 'this' becomes 'window' in a closure.
+
+ /**
+ * Does a substring of shorttext exist within longtext such that the substring
+ * is at least half the length of longtext?
+ * Closure, but does not reference any external variables.
+ * @param {string} longtext Longer string.
+ * @param {string} shorttext Shorter string.
+ * @param {number} i Start index of quarter length substring within longtext.
+ * @return {Array.<string>} Five element Array, containing the prefix of
+ * longtext, the suffix of longtext, the prefix of shorttext, the suffix
+ * of shorttext and the common middle. Or null if there was no match.
+ * @private
+ */
+ function diffHalfMatchI(longtext, shorttext, i) {
+ var seed, j, bestCommon, prefixLength, suffixLength,
+ bestLongtextA, bestLongtextB, bestShorttextA, bestShorttextB;
+ // Start with a 1/4 length substring at position i as a seed.
+ seed = longtext.substring(i, i + Math.floor(longtext.length / 4));
+ j = -1;
+ bestCommon = "";
+ while ((j = shorttext.indexOf(seed, j + 1)) !== -1) {
+ prefixLength = dmp.diffCommonPrefix(longtext.substring(i),
+ shorttext.substring(j));
+ suffixLength = dmp.diffCommonSuffix(longtext.substring(0, i),
+ shorttext.substring(0, j));
+ if (bestCommon.length < suffixLength + prefixLength) {
+ bestCommon = shorttext.substring(j - suffixLength, j) +
+ shorttext.substring(j, j + prefixLength);
+ bestLongtextA = longtext.substring(0, i - suffixLength);
+ bestLongtextB = longtext.substring(i + prefixLength);
+ bestShorttextA = shorttext.substring(0, j - suffixLength);
+ bestShorttextB = shorttext.substring(j + prefixLength);
+ }
+ }
+ if (bestCommon.length * 2 >= longtext.length) {
+ return [ bestLongtextA, bestLongtextB,
+ bestShorttextA, bestShorttextB, bestCommon
+ ];
+ } else {
+ return null;
+ }
+ }
+
+ // First check if the second quarter is the seed for a half-match.
+ hm1 = diffHalfMatchI(longtext, shorttext,
+ Math.ceil(longtext.length / 4));
+ // Check again based on the third quarter.
+ hm2 = diffHalfMatchI(longtext, shorttext,
+ Math.ceil(longtext.length / 2));
+ if (!hm1 && !hm2) {
+ return null;
+ } else if (!hm2) {
+ hm = hm1;
+ } else if (!hm1) {
+ hm = hm2;
+ } else {
+ // Both matched. Select the longest.
+ hm = hm1[4].length > hm2[4].length ? hm1 : hm2;
+ }
+
+ // A half-match was found, sort out the return data.
+ text1A, text1B, text2A, text2B;
+ if (text1.length > text2.length) {
+ text1A = hm[0];
+ text1B = hm[1];
+ text2A = hm[2];
+ text2B = hm[3];
+ } else {
+ text2A = hm[0];
+ text2B = hm[1];
+ text1A = hm[2];
+ text1B = hm[3];
+ }
+ midCommon = hm[4];
+ return [ text1A, text1B, text2A, text2B, midCommon ];
+ };
+
+ /**
+ * Do a quick line-level diff on both strings, then rediff the parts for
+ * greater accuracy.
+ * This speedup can produce non-minimal diffs.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {number} deadline Time when the diff should be complete by.
+ * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffLineMode = function(text1, text2, deadline) {
+ var a, diffs, linearray, pointer, countInsert,
+ countDelete, textInsert, textDelete, j;
+ // Scan the text on a line-by-line basis first.
+ a = this.diffLinesToChars(text1, text2);
+ text1 = a.chars1;
+ text2 = a.chars2;
+ linearray = a.lineArray;
+
+ diffs = this.DiffMain(text1, text2, false, deadline);
+
+ // Convert the diff back to original text.
+ this.diffCharsToLines(diffs, linearray);
+ // Eliminate freak matches (e.g. blank lines)
+ this.diffCleanupSemantic(diffs);
+
+ // Rediff any replacement blocks, this time character-by-character.
+ // Add a dummy entry at the end.
+ diffs.push( [ DIFF_EQUAL, "" ] );
+ pointer = 0;
+ countDelete = 0;
+ countInsert = 0;
+ textDelete = "";
+ textInsert = "";
+ while (pointer < diffs.length) {
+ switch ( diffs[pointer][0] ) {
+ case DIFF_INSERT:
+ countInsert++;
+ textInsert += diffs[pointer][1];
+ break;
+ case DIFF_DELETE:
+ countDelete++;
+ textDelete += diffs[pointer][1];
+ break;
+ case DIFF_EQUAL:
+ // Upon reaching an equality, check for prior redundancies.
+ if (countDelete >= 1 && countInsert >= 1) {
+ // Delete the offending records and add the merged ones.
+ diffs.splice(pointer - countDelete - countInsert,
+ countDelete + countInsert);
+ pointer = pointer - countDelete - countInsert;
+ a = this.DiffMain(textDelete, textInsert, false, deadline);
+ for (j = a.length - 1; j >= 0; j--) {
+ diffs.splice( pointer, 0, a[j] );
+ }
+ pointer = pointer + a.length;
+ }
+ countInsert = 0;
+ countDelete = 0;
+ textDelete = "";
+ textInsert = "";
+ break;
+ }
+ pointer++;
+ }
+ diffs.pop(); // Remove the dummy entry at the end.
+
+ return diffs;
+ };
+
+ /**
+ * Find the 'middle snake' of a diff, split the problem in two
+ * and return the recursively constructed diff.
+ * See Myers 1986 paper: An O(ND) Difference Algorithm and Its Variations.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {number} deadline Time at which to bail if not yet complete.
+ * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffBisect = function(text1, text2, deadline) {
+ var text1Length, text2Length, maxD, vOffset, vLength,
+ v1, v2, x, delta, front, k1start, k1end, k2start,
+ k2end, k2Offset, k1Offset, x1, x2, y1, y2, d, k1, k2;
+ // Cache the text lengths to prevent multiple calls.
+ text1Length = text1.length;
+ text2Length = text2.length;
+ maxD = Math.ceil((text1Length + text2Length) / 2);
+ vOffset = maxD;
+ vLength = 2 * maxD;
+ v1 = new Array(vLength);
+ v2 = new Array(vLength);
+ // Setting all elements to -1 is faster in Chrome & Firefox than mixing
+ // integers and undefined.
+ for (x = 0; x < vLength; x++) {
+ v1[x] = -1;
+ v2[x] = -1;
+ }
+ v1[vOffset + 1] = 0;
+ v2[vOffset + 1] = 0;
+ delta = text1Length - text2Length;
+ // If the total number of characters is odd, then the front path will collide
+ // with the reverse path.
+ front = (delta % 2 !== 0);
+ // Offsets for start and end of k loop.
+ // Prevents mapping of space beyond the grid.
+ k1start = 0;
+ k1end = 0;
+ k2start = 0;
+ k2end = 0;
+ for (d = 0; d < maxD; d++) {
+ // Bail out if deadline is reached.
+ if ((new Date()).getTime() > deadline) {
+ break;
+ }
+
+ // Walk the front path one step.
+ for (k1 = -d + k1start; k1 <= d - k1end; k1 += 2) {
+ k1Offset = vOffset + k1;
+ if ( k1 === -d || ( k1 !== d && v1[ k1Offset - 1 ] < v1[ k1Offset + 1 ] ) ) {
+ x1 = v1[k1Offset + 1];
+ } else {
+ x1 = v1[k1Offset - 1] + 1;
+ }
+ y1 = x1 - k1;
+ while (x1 < text1Length && y1 < text2Length &&
+ text1.charAt(x1) === text2.charAt(y1)) {
+ x1++;
+ y1++;
+ }
+ v1[k1Offset] = x1;
+ if (x1 > text1Length) {
+ // Ran off the right of the graph.
+ k1end += 2;
+ } else if (y1 > text2Length) {
+ // Ran off the bottom of the graph.
+ k1start += 2;
+ } else if (front) {
+ k2Offset = vOffset + delta - k1;
+ if (k2Offset >= 0 && k2Offset < vLength && v2[k2Offset] !== -1) {
+ // Mirror x2 onto top-left coordinate system.
+ x2 = text1Length - v2[k2Offset];
+ if (x1 >= x2) {
+ // Overlap detected.
+ return this.diffBisectSplit(text1, text2, x1, y1, deadline);
+ }
+ }
+ }
+ }
+
+ // Walk the reverse path one step.
+ for (k2 = -d + k2start; k2 <= d - k2end; k2 += 2) {
+ k2Offset = vOffset + k2;
+ if ( k2 === -d || (k2 !== d && v2[ k2Offset - 1 ] < v2[ k2Offset + 1 ] ) ) {
+ x2 = v2[k2Offset + 1];
+ } else {
+ x2 = v2[k2Offset - 1] + 1;
+ }
+ y2 = x2 - k2;
+ while (x2 < text1Length && y2 < text2Length &&
+ text1.charAt(text1Length - x2 - 1) ===
+ text2.charAt(text2Length - y2 - 1)) {
+ x2++;
+ y2++;
+ }
+ v2[k2Offset] = x2;
+ if (x2 > text1Length) {
+ // Ran off the left of the graph.
+ k2end += 2;
+ } else if (y2 > text2Length) {
+ // Ran off the top of the graph.
+ k2start += 2;
+ } else if (!front) {
+ k1Offset = vOffset + delta - k2;
+ if (k1Offset >= 0 && k1Offset < vLength && v1[k1Offset] !== -1) {
+ x1 = v1[k1Offset];
+ y1 = vOffset + x1 - k1Offset;
+ // Mirror x2 onto top-left coordinate system.
+ x2 = text1Length - x2;
+ if (x1 >= x2) {
+ // Overlap detected.
+ return this.diffBisectSplit(text1, text2, x1, y1, deadline);
+ }
+ }
+ }
+ }
+ }
+ // Diff took too long and hit the deadline or
+ // number of diffs equals number of characters, no commonality at all.
+ return [
+ [ DIFF_DELETE, text1 ],
+ [ DIFF_INSERT, text2 ]
+ ];
+ };
+
+ /**
+ * Given the location of the 'middle snake', split the diff in two parts
+ * and recurse.
+ * @param {string} text1 Old string to be diffed.
+ * @param {string} text2 New string to be diffed.
+ * @param {number} x Index of split point in text1.
+ * @param {number} y Index of split point in text2.
+ * @param {number} deadline Time at which to bail if not yet complete.
+ * @return {!Array.<!DiffMatchPatch.Diff>} Array of diff tuples.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffBisectSplit = function( text1, text2, x, y, deadline ) {
+ var text1a, text1b, text2a, text2b, diffs, diffsb;
+ text1a = text1.substring(0, x);
+ text2a = text2.substring(0, y);
+ text1b = text1.substring(x);
+ text2b = text2.substring(y);
+
+ // Compute both diffs serially.
+ diffs = this.DiffMain(text1a, text2a, false, deadline);
+ diffsb = this.DiffMain(text1b, text2b, false, deadline);
+
+ return diffs.concat(diffsb);
+ };
+
+ /**
+ * Reduce the number of edits by eliminating semantically trivial equalities.
+ * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
+ */
+ DiffMatchPatch.prototype.diffCleanupSemantic = function(diffs) {
+ var changes, equalities, equalitiesLength, lastequality,
+ pointer, lengthInsertions2, lengthDeletions2, lengthInsertions1,
+ lengthDeletions1, deletion, insertion, overlapLength1, overlapLength2;
+ changes = false;
+ equalities = []; // Stack of indices where equalities are found.
+ equalitiesLength = 0; // Keeping our own length var is faster in JS.
+ /** @type {?string} */
+ lastequality = null;
+ // Always equal to diffs[equalities[equalitiesLength - 1]][1]
+ pointer = 0; // Index of current position.
+ // Number of characters that changed prior to the equality.
+ lengthInsertions1 = 0;
+ lengthDeletions1 = 0;
+ // Number of characters that changed after the equality.
+ lengthInsertions2 = 0;
+ lengthDeletions2 = 0;
+ while (pointer < diffs.length) {
+ if (diffs[pointer][0] === DIFF_EQUAL) { // Equality found.
+ equalities[equalitiesLength++] = pointer;
+ lengthInsertions1 = lengthInsertions2;
+ lengthDeletions1 = lengthDeletions2;
+ lengthInsertions2 = 0;
+ lengthDeletions2 = 0;
+ lastequality = diffs[pointer][1];
+ } else { // An insertion or deletion.
+ if (diffs[pointer][0] === DIFF_INSERT) {
+ lengthInsertions2 += diffs[pointer][1].length;
+ } else {
+ lengthDeletions2 += diffs[pointer][1].length;
+ }
+ // Eliminate an equality that is smaller or equal to the edits on both
+ // sides of it.
+ if (lastequality && (lastequality.length <=
+ Math.max(lengthInsertions1, lengthDeletions1)) &&
+ (lastequality.length <= Math.max(lengthInsertions2,
+ lengthDeletions2))) {
+ // Duplicate record.
+ diffs.splice( equalities[ equalitiesLength - 1 ], 0, [ DIFF_DELETE, lastequality ] );
+ // Change second copy to insert.
+ diffs[equalities[equalitiesLength - 1] + 1][0] = DIFF_INSERT;
+ // Throw away the equality we just deleted.
+ equalitiesLength--;
+ // Throw away the previous equality (it needs to be reevaluated).
+ equalitiesLength--;
+ pointer = equalitiesLength > 0 ? equalities[equalitiesLength - 1] : -1;
+ lengthInsertions1 = 0; // Reset the counters.
+ lengthDeletions1 = 0;
+ lengthInsertions2 = 0;
+ lengthDeletions2 = 0;
+ lastequality = null;
+ changes = true;
+ }
+ }
+ pointer++;
+ }
+
+ // Normalize the diff.
+ if (changes) {
+ this.diffCleanupMerge(diffs);
+ }
+
+ // Find any overlaps between deletions and insertions.
+ // e.g: <del>abcxxx</del><ins>xxxdef</ins>
+ // -> <del>abc</del>xxx<ins>def</ins>
+ // e.g: <del>xxxabc</del><ins>defxxx</ins>
+ // -> <ins>def</ins>xxx<del>abc</del>
+ // Only extract an overlap if it is as big as the edit ahead or behind it.
+ pointer = 1;
+ while (pointer < diffs.length) {
+ if (diffs[pointer - 1][0] === DIFF_DELETE &&
+ diffs[pointer][0] === DIFF_INSERT) {
+ deletion = diffs[pointer - 1][1];
+ insertion = diffs[pointer][1];
+ overlapLength1 = this.diffCommonOverlap(deletion, insertion);
+ overlapLength2 = this.diffCommonOverlap(insertion, deletion);
+ if (overlapLength1 >= overlapLength2) {
+ if (overlapLength1 >= deletion.length / 2 ||
+ overlapLength1 >= insertion.length / 2) {
+ // Overlap found. Insert an equality and trim the surrounding edits.
+ diffs.splice( pointer, 0, [ DIFF_EQUAL, insertion.substring( 0, overlapLength1 ) ] );
+ diffs[pointer - 1][1] =
+ deletion.substring(0, deletion.length - overlapLength1);
+ diffs[pointer + 1][1] = insertion.substring(overlapLength1);
+ pointer++;
+ }
+ } else {
+ if (overlapLength2 >= deletion.length / 2 ||
+ overlapLength2 >= insertion.length / 2) {
+ // Reverse overlap found.
+ // Insert an equality and swap and trim the surrounding edits.
+ diffs.splice( pointer, 0, [ DIFF_EQUAL, deletion.substring( 0, overlapLength2 ) ] );
+ diffs[pointer - 1][0] = DIFF_INSERT;
+ diffs[pointer - 1][1] =
+ insertion.substring(0, insertion.length - overlapLength2);
+ diffs[pointer + 1][0] = DIFF_DELETE;
+ diffs[pointer + 1][1] =
+ deletion.substring(overlapLength2);
+ pointer++;
+ }
+ }
+ pointer++;
+ }
+ pointer++;
+ }
+ };
+
+ /**
+ * Determine if the suffix of one string is the prefix of another.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {number} The number of characters common to the end of the first
+ * string and the start of the second string.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffCommonOverlap = function(text1, text2) {
+ var text1Length, text2Length, textLength,
+ best, length, pattern, found;
+ // Cache the text lengths to prevent multiple calls.
+ text1Length = text1.length;
+ text2Length = text2.length;
+ // Eliminate the null case.
+ if (text1Length === 0 || text2Length === 0) {
+ return 0;
+ }
+ // Truncate the longer string.
+ if (text1Length > text2Length) {
+ text1 = text1.substring(text1Length - text2Length);
+ } else if (text1Length < text2Length) {
+ text2 = text2.substring(0, text1Length);
+ }
+ textLength = Math.min(text1Length, text2Length);
+ // Quick check for the worst case.
+ if (text1 === text2) {
+ return textLength;
+ }
+
+ // Start by looking for a single character match
+ // and increase length until no match is found.
+ // Performance analysis: http://neil.fraser.name/news/2010/11/04/
+ best = 0;
+ length = 1;
+ while (true) {
+ pattern = text1.substring(textLength - length);
+ found = text2.indexOf(pattern);
+ if (found === -1) {
+ return best;
+ }
+ length += found;
+ if (found === 0 || text1.substring(textLength - length) ===
+ text2.substring(0, length)) {
+ best = length;
+ length++;
+ }
+ }
+ };
+
+ /**
+ * Split two texts into an array of strings. Reduce the texts to a string of
+ * hashes where each Unicode character represents one line.
+ * @param {string} text1 First string.
+ * @param {string} text2 Second string.
+ * @return {{chars1: string, chars2: string, lineArray: !Array.<string>}}
+ * An object containing the encoded text1, the encoded text2 and
+ * the array of unique strings.
+ * The zeroth element of the array of unique strings is intentionally blank.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffLinesToChars = function(text1, text2) {
+ var lineArray, lineHash, chars1, chars2;
+ lineArray = []; // e.g. lineArray[4] === 'Hello\n'
+ lineHash = {}; // e.g. lineHash['Hello\n'] === 4
+
+ // '\x00' is a valid character, but various debuggers don't like it.
+ // So we'll insert a junk entry to avoid generating a null character.
+ lineArray[0] = "";
+
+ /**
+ * Split a text into an array of strings. Reduce the texts to a string of
+ * hashes where each Unicode character represents one line.
+ * Modifies linearray and linehash through being a closure.
+ * @param {string} text String to encode.
+ * @return {string} Encoded string.
+ * @private
+ */
+ function diffLinesToCharsMunge(text) {
+ var chars, lineStart, lineEnd, lineArrayLength, line;
+ chars = "";
+ // Walk the text, pulling out a substring for each line.
+ // text.split('\n') would would temporarily double our memory footprint.
+ // Modifying text would create many large strings to garbage collect.
+ lineStart = 0;
+ lineEnd = -1;
+ // Keeping our own length variable is faster than looking it up.
+ lineArrayLength = lineArray.length;
+ while (lineEnd < text.length - 1) {
+ lineEnd = text.indexOf("\n", lineStart);
+ if (lineEnd === -1) {
+ lineEnd = text.length - 1;
+ }
+ line = text.substring(lineStart, lineEnd + 1);
+ lineStart = lineEnd + 1;
+
+ if (lineHash.hasOwnProperty ? lineHash.hasOwnProperty(line) :
+ (lineHash[line] !== undefined)) {
+ chars += String.fromCharCode( lineHash[ line ] );
+ } else {
+ chars += String.fromCharCode(lineArrayLength);
+ lineHash[line] = lineArrayLength;
+ lineArray[lineArrayLength++] = line;
+ }
+ }
+ return chars;
+ }
+
+ chars1 = diffLinesToCharsMunge(text1);
+ chars2 = diffLinesToCharsMunge(text2);
+ return {
+ chars1: chars1,
+ chars2: chars2,
+ lineArray: lineArray
+ };
+ };
+
+ /**
+ * Rehydrate the text in a diff from a string of line hashes to real lines of
+ * text.
+ * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
+ * @param {!Array.<string>} lineArray Array of unique strings.
+ * @private
+ */
+ DiffMatchPatch.prototype.diffCharsToLines = function( diffs, lineArray ) {
+ var x, chars, text, y;
+ for ( x = 0; x < diffs.length; x++ ) {
+ chars = diffs[x][1];
+ text = [];
+ for ( y = 0; y < chars.length; y++ ) {
+ text[y] = lineArray[chars.charCodeAt(y)];
+ }
+ diffs[x][1] = text.join("");
+ }
+ };
+
+ /**
+ * Reorder and merge like edit sections. Merge equalities.
+ * Any edit section can move as long as it doesn't cross an equality.
+ * @param {!Array.<!DiffMatchPatch.Diff>} diffs Array of diff tuples.
+ */
+ DiffMatchPatch.prototype.diffCleanupMerge = function(diffs) {
+ var pointer, countDelete, countInsert, textInsert, textDelete,
+ commonlength, changes;
+ diffs.push( [ DIFF_EQUAL, "" ] ); // Add a dummy entry at the end.
+ pointer = 0;
+ countDelete = 0;
+ countInsert = 0;
+ textDelete = "";
+ textInsert = "";
+ commonlength;
+ while (pointer < diffs.length) {
+ switch ( diffs[ pointer ][ 0 ] ) {
+ case DIFF_INSERT:
+ countInsert++;
+ textInsert += diffs[pointer][1];
+ pointer++;
+ break;
+ case DIFF_DELETE:
+ countDelete++;
+ textDelete += diffs[pointer][1];
+ pointer++;
+ break;
+ case DIFF_EQUAL:
+ // Upon reaching an equality, check for prior redundancies.
+ if (countDelete + countInsert > 1) {
+ if (countDelete !== 0 && countInsert !== 0) {
+ // Factor out any common prefixies.
+ commonlength = this.diffCommonPrefix(textInsert, textDelete);
+ if (commonlength !== 0) {
+ if ((pointer - countDelete - countInsert) > 0 &&
+ diffs[pointer - countDelete - countInsert - 1][0] ===
+ DIFF_EQUAL) {
+ diffs[pointer - countDelete - countInsert - 1][1] +=
+ textInsert.substring(0, commonlength);
+ } else {
+ diffs.splice( 0, 0, [ DIFF_EQUAL,
+ textInsert.substring( 0, commonlength )
+ ] );
+ pointer++;
+ }
+ textInsert = textInsert.substring(commonlength);
+ textDelete = textDelete.substring(commonlength);
+ }
+ // Factor out any common suffixies.
+ commonlength = this.diffCommonSuffix(textInsert, textDelete);
+ if (commonlength !== 0) {
+ diffs[pointer][1] = textInsert.substring(textInsert.length -
+ commonlength) + diffs[pointer][1];
+ textInsert = textInsert.substring(0, textInsert.length -
+ commonlength);
+ textDelete = textDelete.substring(0, textDelete.length -
+ commonlength);
+ }
+ }
+ // Delete the offending records and add the merged ones.
+ if (countDelete === 0) {
+ diffs.splice( pointer - countInsert,
+ countDelete + countInsert, [ DIFF_INSERT, textInsert ] );
+ } else if (countInsert === 0) {
+ diffs.splice( pointer - countDelete,
+ countDelete + countInsert, [ DIFF_DELETE, textDelete ] );
+ } else {
+ diffs.splice( pointer - countDelete - countInsert,
+ countDelete + countInsert, [ DIFF_DELETE, textDelete ], [ DIFF_INSERT, textInsert ] );
+ }
+ pointer = pointer - countDelete - countInsert +
+ (countDelete ? 1 : 0) + (countInsert ? 1 : 0) + 1;
+ } else if (pointer !== 0 && diffs[pointer - 1][0] === DIFF_EQUAL) {
+ // Merge this equality with the previous one.
+ diffs[pointer - 1][1] += diffs[pointer][1];
+ diffs.splice(pointer, 1);
+ } else {
+ pointer++;
+ }
+ countInsert = 0;
+ countDelete = 0;
+ textDelete = "";
+ textInsert = "";
+ break;
+ }
+ }
+ if (diffs[diffs.length - 1][1] === "") {
+ diffs.pop(); // Remove the dummy entry at the end.
+ }
+
+ // Second pass: look for single edits surrounded on both sides by equalities
+ // which can be shifted sideways to eliminate an equality.
+ // e.g: A<ins>BA</ins>C -> <ins>AB</ins>AC
+ changes = false;
+ pointer = 1;
+ // Intentionally ignore the first and last element (don't need checking).
+ while (pointer < diffs.length - 1) {
+ if (diffs[pointer - 1][0] === DIFF_EQUAL &&
+ diffs[pointer + 1][0] === DIFF_EQUAL) {
+ // This is a single edit surrounded by equalities.
+ if ( diffs[ pointer ][ 1 ].substring( diffs[ pointer ][ 1 ].length -
+ diffs[ pointer - 1 ][ 1 ].length ) === diffs[ pointer - 1 ][ 1 ] ) {
+ // Shift the edit over the previous equality.
+ diffs[pointer][1] = diffs[pointer - 1][1] +
+ diffs[pointer][1].substring(0, diffs[pointer][1].length -
+ diffs[pointer - 1][1].length);
+ diffs[pointer + 1][1] = diffs[pointer - 1][1] + diffs[pointer + 1][1];
+ diffs.splice(pointer - 1, 1);
+ changes = true;
+ } else if ( diffs[ pointer ][ 1 ].substring( 0, diffs[ pointer + 1 ][ 1 ].length ) ===
+ diffs[ pointer + 1 ][ 1 ] ) {
+ // Shift the edit over the next equality.
+ diffs[pointer - 1][1] += diffs[pointer + 1][1];
+ diffs[pointer][1] =
+ diffs[pointer][1].substring(diffs[pointer + 1][1].length) +
+ diffs[pointer + 1][1];
+ diffs.splice(pointer + 1, 1);
+ changes = true;
+ }
+ }
+ pointer++;
+ }
+ // If shifts were made, the diff needs reordering and another shift sweep.
+ if (changes) {
+ this.diffCleanupMerge(diffs);
+ }
+ };
+
+ return function(o, n) {
+ var diff, output, text;
+ diff = new DiffMatchPatch();
+ output = diff.DiffMain(o, n);
+ //console.log(output);
+ diff.diffCleanupEfficiency(output);
+ text = diff.diffPrettyHtml(output);
+
+ return text;
+ };
}());
// jscs:enable
@@ -2256,7 +3176,14 @@ function addEvent( elem, type, fn ) {
} else if ( elem.attachEvent ) {
// support: IE <9
- elem.attachEvent( "on" + type, fn );
+ elem.attachEvent( "on" + type, function() {
+ var event = window.event;
+ if ( !event.target ) {
+ event.target = event.srcElement || document;
+ }
+
+ fn.call( elem, event );
+ });
}
}
@@ -2427,12 +3354,16 @@ function setUrl( params ) {
}
function applyUrlParams() {
- var selectBox = id( "qunit-modulefilter" ),
- selection = decodeURIComponent( selectBox.options[ selectBox.selectedIndex ].value ),
+ var selectedModule,
+ modulesList = id( "qunit-modulefilter" ),
filter = id( "qunit-filter-input" ).value;
+ selectedModule = modulesList ?
+ decodeURIComponent( modulesList.options[ modulesList.selectedIndex ].value ) :
+ undefined;
+
window.location = setUrl({
- module: ( selection === "" ) ? undefined : selection,
+ module: ( selectedModule === "" ) ? undefined : selectedModule,
filter: ( filter === "" ) ? undefined : filter,
// Remove testId filter
@@ -2588,9 +3519,14 @@ function storeFixture() {
function appendUserAgent() {
var userAgent = id( "qunit-userAgent" );
+
if ( userAgent ) {
userAgent.innerHTML = "";
- userAgent.appendChild( document.createTextNode( navigator.userAgent ) );
+ userAgent.appendChild(
+ document.createTextNode(
+ "QUnit " + QUnit.version + "; " + navigator.userAgent
+ )
+ );
}
}
@@ -2733,7 +3669,7 @@ function getNameHtml( name, module ) {
}
QUnit.testStart(function( details ) {
- var running, testBlock;
+ var running, testBlock, bad;
testBlock = id( "qunit-test-output-" + details.testId );
if ( testBlock ) {
@@ -2746,7 +3682,13 @@ QUnit.testStart(function( details ) {
running = id( "qunit-testresult" );
if ( running ) {
- running.innerHTML = "Running: <br />" + getNameHtml( details.name, details.module );
+ bad = QUnit.config.reorder && defined.sessionStorage &&
+ +sessionStorage.getItem( "qunit-test-" + details.module + "-" + details.name );
+
+ running.innerHTML = ( bad ?
+ "Rerunning previously failed test: <br />" :
+ "Running: <br />" ) +
+ getNameHtml( details.name, details.module );
}
});
@@ -2779,6 +3721,15 @@ QUnit.log(function( details ) {
actual + "</pre></td></tr>" +
"<tr class='test-diff'><th>Diff: </th><td><pre>" +
QUnit.diff( expected, actual ) + "</pre></td></tr>";
+ } else {
+ if ( expected.indexOf( "[object Array]" ) !== -1 ||
+ expected.indexOf( "[object Object]" ) !== -1 ) {
+ message += "<tr class='test-message'><th>Message: </th><td>" +
+ "Diff suppressed as the depth of object is more than current max depth (" +
+ QUnit.config.maxDepth + ").<p>Hint: Use <code>QUnit.dump.maxDepth</code> to " +
+ " run with a higher max depth or <a href='" + setUrl({ maxDepth: -1 }) + "'>" +
+ "Rerun</a> without max depth.</p></td></tr>";
+ }
}
if ( details.source ) {
@@ -2863,13 +3814,15 @@ QUnit.testDone(function( details ) {
}
});
-if ( !defined.document || document.readyState === "complete" ) {
+if ( defined.document ) {
+ if ( document.readyState === "complete" ) {
+ QUnit.load();
+ } else {
+ addEvent( window, "load", QUnit.load );
+ }
+} else {
config.pageLoaded = true;
config.autorun = true;
}
-if ( defined.document ) {
- addEvent( window, "load", QUnit.load );
-}
-
})();
diff --git a/resources/lib/sinonjs/sinon-1.10.3.js b/resources/lib/sinonjs/sinon-1.10.3.js
deleted file mode 100644
index 703414dd..00000000
--- a/resources/lib/sinonjs/sinon-1.10.3.js
+++ /dev/null
@@ -1,5073 +0,0 @@
-/**
- * Sinon.JS 1.10.3, 2014/07/11
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
- *
- * (The BSD License)
- *
- * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- *
- * * Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * * Neither the name of Christian Johansen nor the names of his contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-this.sinon = (function () {
-var samsam, formatio;
-function define(mod, deps, fn) { if (mod == "samsam") { samsam = deps(); } else if (typeof fn === "function") { formatio = fn(samsam); } }
-define.amd = {};
-((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
- (typeof module === "object" &&
- function (m) { module.exports = m(); }) || // Node
- function (m) { this.samsam = m(); } // Browser globals
-)(function () {
- var o = Object.prototype;
- var div = typeof document !== "undefined" && document.createElement("div");
-
- function isNaN(value) {
- // Unlike global isNaN, this avoids type coercion
- // typeof check avoids IE host object issues, hat tip to
- // lodash
- var val = value; // JsLint thinks value !== value is "weird"
- return typeof value === "number" && value !== val;
- }
-
- function getClass(value) {
- // Returns the internal [[Class]] by calling Object.prototype.toString
- // with the provided value as this. Return value is a string, naming the
- // internal class, e.g. "Array"
- return o.toString.call(value).split(/[ \]]/)[1];
- }
-
- /**
- * @name samsam.isArguments
- * @param Object object
- *
- * Returns ``true`` if ``object`` is an ``arguments`` object,
- * ``false`` otherwise.
- */
- function isArguments(object) {
- if (typeof object !== "object" || typeof object.length !== "number" ||
- getClass(object) === "Array") {
- return false;
- }
- if (typeof object.callee == "function") { return true; }
- try {
- object[object.length] = 6;
- delete object[object.length];
- } catch (e) {
- return true;
- }
- return false;
- }
-
- /**
- * @name samsam.isElement
- * @param Object object
- *
- * Returns ``true`` if ``object`` is a DOM element node. Unlike
- * Underscore.js/lodash, this function will return ``false`` if ``object``
- * is an *element-like* object, i.e. a regular object with a ``nodeType``
- * property that holds the value ``1``.
- */
- function isElement(object) {
- if (!object || object.nodeType !== 1 || !div) { return false; }
- try {
- object.appendChild(div);
- object.removeChild(div);
- } catch (e) {
- return false;
- }
- return true;
- }
-
- /**
- * @name samsam.keys
- * @param Object object
- *
- * Return an array of own property names.
- */
- function keys(object) {
- var ks = [], prop;
- for (prop in object) {
- if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
- }
- return ks;
- }
-
- /**
- * @name samsam.isDate
- * @param Object value
- *
- * Returns true if the object is a ``Date``, or *date-like*. Duck typing
- * of date objects work by checking that the object has a ``getTime``
- * function whose return value equals the return value from the object's
- * ``valueOf``.
- */
- function isDate(value) {
- return typeof value.getTime == "function" &&
- value.getTime() == value.valueOf();
- }
-
- /**
- * @name samsam.isNegZero
- * @param Object value
- *
- * Returns ``true`` if ``value`` is ``-0``.
- */
- function isNegZero(value) {
- return value === 0 && 1 / value === -Infinity;
- }
-
- /**
- * @name samsam.equal
- * @param Object obj1
- * @param Object obj2
- *
- * Returns ``true`` if two objects are strictly equal. Compared to
- * ``===`` there are two exceptions:
- *
- * - NaN is considered equal to NaN
- * - -0 and +0 are not considered equal
- */
- function identical(obj1, obj2) {
- if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
- return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
- }
- }
-
-
- /**
- * @name samsam.deepEqual
- * @param Object obj1
- * @param Object obj2
- *
- * Deep equal comparison. Two values are "deep equal" if:
- *
- * - They are equal, according to samsam.identical
- * - They are both date objects representing the same time
- * - They are both arrays containing elements that are all deepEqual
- * - They are objects with the same set of properties, and each property
- * in ``obj1`` is deepEqual to the corresponding property in ``obj2``
- *
- * Supports cyclic objects.
- */
- function deepEqualCyclic(obj1, obj2) {
-
- // used for cyclic comparison
- // contain already visited objects
- var objects1 = [],
- objects2 = [],
- // contain pathes (position in the object structure)
- // of the already visited objects
- // indexes same as in objects arrays
- paths1 = [],
- paths2 = [],
- // contains combinations of already compared objects
- // in the manner: { "$1['ref']$2['ref']": true }
- compared = {};
-
- /**
- * used to check, if the value of a property is an object
- * (cyclic logic is only needed for objects)
- * only needed for cyclic logic
- */
- function isObject(value) {
-
- if (typeof value === 'object' && value !== null &&
- !(value instanceof Boolean) &&
- !(value instanceof Date) &&
- !(value instanceof Number) &&
- !(value instanceof RegExp) &&
- !(value instanceof String)) {
-
- return true;
- }
-
- return false;
- }
-
- /**
- * returns the index of the given object in the
- * given objects array, -1 if not contained
- * only needed for cyclic logic
- */
- function getIndex(objects, obj) {
-
- var i;
- for (i = 0; i < objects.length; i++) {
- if (objects[i] === obj) {
- return i;
- }
- }
-
- return -1;
- }
-
- // does the recursion for the deep equal check
- return (function deepEqual(obj1, obj2, path1, path2) {
- var type1 = typeof obj1;
- var type2 = typeof obj2;
-
- // == null also matches undefined
- if (obj1 === obj2 ||
- isNaN(obj1) || isNaN(obj2) ||
- obj1 == null || obj2 == null ||
- type1 !== "object" || type2 !== "object") {
-
- return identical(obj1, obj2);
- }
-
- // Elements are only equal if identical(expected, actual)
- if (isElement(obj1) || isElement(obj2)) { return false; }
-
- var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
- if (isDate1 || isDate2) {
- if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
- return false;
- }
- }
-
- if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
- if (obj1.toString() !== obj2.toString()) { return false; }
- }
-
- var class1 = getClass(obj1);
- var class2 = getClass(obj2);
- var keys1 = keys(obj1);
- var keys2 = keys(obj2);
-
- if (isArguments(obj1) || isArguments(obj2)) {
- if (obj1.length !== obj2.length) { return false; }
- } else {
- if (type1 !== type2 || class1 !== class2 ||
- keys1.length !== keys2.length) {
- return false;
- }
- }
-
- var key, i, l,
- // following vars are used for the cyclic logic
- value1, value2,
- isObject1, isObject2,
- index1, index2,
- newPath1, newPath2;
-
- for (i = 0, l = keys1.length; i < l; i++) {
- key = keys1[i];
- if (!o.hasOwnProperty.call(obj2, key)) {
- return false;
- }
-
- // Start of the cyclic logic
-
- value1 = obj1[key];
- value2 = obj2[key];
-
- isObject1 = isObject(value1);
- isObject2 = isObject(value2);
-
- // determine, if the objects were already visited
- // (it's faster to check for isObject first, than to
- // get -1 from getIndex for non objects)
- index1 = isObject1 ? getIndex(objects1, value1) : -1;
- index2 = isObject2 ? getIndex(objects2, value2) : -1;
-
- // determine the new pathes of the objects
- // - for non cyclic objects the current path will be extended
- // by current property name
- // - for cyclic objects the stored path is taken
- newPath1 = index1 !== -1
- ? paths1[index1]
- : path1 + '[' + JSON.stringify(key) + ']';
- newPath2 = index2 !== -1
- ? paths2[index2]
- : path2 + '[' + JSON.stringify(key) + ']';
-
- // stop recursion if current objects are already compared
- if (compared[newPath1 + newPath2]) {
- return true;
- }
-
- // remember the current objects and their pathes
- if (index1 === -1 && isObject1) {
- objects1.push(value1);
- paths1.push(newPath1);
- }
- if (index2 === -1 && isObject2) {
- objects2.push(value2);
- paths2.push(newPath2);
- }
-
- // remember that the current objects are already compared
- if (isObject1 && isObject2) {
- compared[newPath1 + newPath2] = true;
- }
-
- // End of cyclic logic
-
- // neither value1 nor value2 is a cycle
- // continue with next level
- if (!deepEqual(value1, value2, newPath1, newPath2)) {
- return false;
- }
- }
-
- return true;
-
- }(obj1, obj2, '$1', '$2'));
- }
-
- var match;
-
- function arrayContains(array, subset) {
- if (subset.length === 0) { return true; }
- var i, l, j, k;
- for (i = 0, l = array.length; i < l; ++i) {
- if (match(array[i], subset[0])) {
- for (j = 0, k = subset.length; j < k; ++j) {
- if (!match(array[i + j], subset[j])) { return false; }
- }
- return true;
- }
- }
- return false;
- }
-
- /**
- * @name samsam.match
- * @param Object object
- * @param Object matcher
- *
- * Compare arbitrary value ``object`` with matcher.
- */
- match = function match(object, matcher) {
- if (matcher && typeof matcher.test === "function") {
- return matcher.test(object);
- }
-
- if (typeof matcher === "function") {
- return matcher(object) === true;
- }
-
- if (typeof matcher === "string") {
- matcher = matcher.toLowerCase();
- var notNull = typeof object === "string" || !!object;
- return notNull &&
- (String(object)).toLowerCase().indexOf(matcher) >= 0;
- }
-
- if (typeof matcher === "number") {
- return matcher === object;
- }
-
- if (typeof matcher === "boolean") {
- return matcher === object;
- }
-
- if (getClass(object) === "Array" && getClass(matcher) === "Array") {
- return arrayContains(object, matcher);
- }
-
- if (matcher && typeof matcher === "object") {
- var prop;
- for (prop in matcher) {
- if (!match(object[prop], matcher[prop])) {
- return false;
- }
- }
- return true;
- }
-
- throw new Error("Matcher was not a string, a number, a " +
- "function, a boolean or an object");
- };
-
- return {
- isArguments: isArguments,
- isElement: isElement,
- isDate: isDate,
- isNegZero: isNegZero,
- identical: identical,
- deepEqual: deepEqualCyclic,
- match: match,
- keys: keys
- };
-});
-((typeof define === "function" && define.amd && function (m) {
- define("formatio", ["samsam"], m);
-}) || (typeof module === "object" && function (m) {
- module.exports = m(require("samsam"));
-}) || function (m) { this.formatio = m(this.samsam); }
-)(function (samsam) {
-
- var formatio = {
- excludeConstructors: ["Object", /^.$/],
- quoteStrings: true
- };
-
- var hasOwn = Object.prototype.hasOwnProperty;
-
- var specialObjects = [];
- if (typeof global !== "undefined") {
- specialObjects.push({ object: global, value: "[object global]" });
- }
- if (typeof document !== "undefined") {
- specialObjects.push({
- object: document,
- value: "[object HTMLDocument]"
- });
- }
- if (typeof window !== "undefined") {
- specialObjects.push({ object: window, value: "[object Window]" });
- }
-
- function functionName(func) {
- if (!func) { return ""; }
- if (func.displayName) { return func.displayName; }
- if (func.name) { return func.name; }
- var matches = func.toString().match(/function\s+([^\(]+)/m);
- return (matches && matches[1]) || "";
- }
-
- function constructorName(f, object) {
- var name = functionName(object && object.constructor);
- var excludes = f.excludeConstructors ||
- formatio.excludeConstructors || [];
-
- var i, l;
- for (i = 0, l = excludes.length; i < l; ++i) {
- if (typeof excludes[i] === "string" && excludes[i] === name) {
- return "";
- } else if (excludes[i].test && excludes[i].test(name)) {
- return "";
- }
- }
-
- return name;
- }
-
- function isCircular(object, objects) {
- if (typeof object !== "object") { return false; }
- var i, l;
- for (i = 0, l = objects.length; i < l; ++i) {
- if (objects[i] === object) { return true; }
- }
- return false;
- }
-
- function ascii(f, object, processed, indent) {
- if (typeof object === "string") {
- var qs = f.quoteStrings;
- var quote = typeof qs !== "boolean" || qs;
- return processed || quote ? '"' + object + '"' : object;
- }
-
- if (typeof object === "function" && !(object instanceof RegExp)) {
- return ascii.func(object);
- }
-
- processed = processed || [];
-
- if (isCircular(object, processed)) { return "[Circular]"; }
-
- if (Object.prototype.toString.call(object) === "[object Array]") {
- return ascii.array.call(f, object, processed);
- }
-
- if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
- if (samsam.isElement(object)) { return ascii.element(object); }
-
- if (typeof object.toString === "function" &&
- object.toString !== Object.prototype.toString) {
- return object.toString();
- }
-
- var i, l;
- for (i = 0, l = specialObjects.length; i < l; i++) {
- if (object === specialObjects[i].object) {
- return specialObjects[i].value;
- }
- }
-
- return ascii.object.call(f, object, processed, indent);
- }
-
- ascii.func = function (func) {
- return "function " + functionName(func) + "() {}";
- };
-
- ascii.array = function (array, processed) {
- processed = processed || [];
- processed.push(array);
- var i, l, pieces = [];
- for (i = 0, l = array.length; i < l; ++i) {
- pieces.push(ascii(this, array[i], processed));
- }
- return "[" + pieces.join(", ") + "]";
- };
-
- ascii.object = function (object, processed, indent) {
- processed = processed || [];
- processed.push(object);
- indent = indent || 0;
- var pieces = [], properties = samsam.keys(object).sort();
- var length = 3;
- var prop, str, obj, i, l;
-
- for (i = 0, l = properties.length; i < l; ++i) {
- prop = properties[i];
- obj = object[prop];
-
- if (isCircular(obj, processed)) {
- str = "[Circular]";
- } else {
- str = ascii(this, obj, processed, indent + 2);
- }
-
- str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
- length += str.length;
- pieces.push(str);
- }
-
- var cons = constructorName(this, object);
- var prefix = cons ? "[" + cons + "] " : "";
- var is = "";
- for (i = 0, l = indent; i < l; ++i) { is += " "; }
-
- if (length + indent > 80) {
- return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" +
- is + "}";
- }
- return prefix + "{ " + pieces.join(", ") + " }";
- };
-
- ascii.element = function (element) {
- var tagName = element.tagName.toLowerCase();
- var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
-
- for (i = 0, l = attrs.length; i < l; ++i) {
- attr = attrs.item(i);
- attrName = attr.nodeName.toLowerCase().replace("html:", "");
- val = attr.nodeValue;
- if (attrName !== "contenteditable" || val !== "inherit") {
- if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
- }
- }
-
- var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
- var content = element.innerHTML;
-
- if (content.length > 20) {
- content = content.substr(0, 20) + "[...]";
- }
-
- var res = formatted + pairs.join(" ") + ">" + content +
- "</" + tagName + ">";
-
- return res.replace(/ contentEditable="inherit"/, "");
- };
-
- function Formatio(options) {
- for (var opt in options) {
- this[opt] = options[opt];
- }
- }
-
- Formatio.prototype = {
- functionName: functionName,
-
- configure: function (options) {
- return new Formatio(options);
- },
-
- constructorName: function (object) {
- return constructorName(this, object);
- },
-
- ascii: function (object, processed, indent) {
- return ascii(this, object, processed, indent);
- }
- };
-
- return Formatio.prototype;
-});
-/*jslint eqeqeq: false, onevar: false, forin: true, nomen: false, regexp: false, plusplus: false*/
-/*global module, require, __dirname, document*/
-/**
- * Sinon core utilities. For internal use only.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-var sinon = (function (formatio) {
- var div = typeof document != "undefined" && document.createElement("div");
- var hasOwn = Object.prototype.hasOwnProperty;
-
- function isDOMNode(obj) {
- var success = false;
-
- try {
- obj.appendChild(div);
- success = div.parentNode == obj;
- } catch (e) {
- return false;
- } finally {
- try {
- obj.removeChild(div);
- } catch (e) {
- // Remove failed, not much we can do about that
- }
- }
-
- return success;
- }
-
- function isElement(obj) {
- return div && obj && obj.nodeType === 1 && isDOMNode(obj);
- }
-
- function isFunction(obj) {
- return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
- }
-
- function isReallyNaN(val) {
- return typeof val === 'number' && isNaN(val);
- }
-
- function mirrorProperties(target, source) {
- for (var prop in source) {
- if (!hasOwn.call(target, prop)) {
- target[prop] = source[prop];
- }
- }
- }
-
- function isRestorable (obj) {
- return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
- }
-
- var sinon = {
- wrapMethod: function wrapMethod(object, property, method) {
- if (!object) {
- throw new TypeError("Should wrap property of object");
- }
-
- if (typeof method != "function") {
- throw new TypeError("Method wrapper should be function");
- }
-
- var wrappedMethod = object[property],
- error;
-
- if (!isFunction(wrappedMethod)) {
- error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
- property + " as function");
- } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
- error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
- } else if (wrappedMethod.calledBefore) {
- var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
- error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
- }
-
- if (error) {
- if (wrappedMethod && wrappedMethod._stack) {
- error.stack += '\n--------------\n' + wrappedMethod._stack;
- }
- throw error;
- }
-
- // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
- // when using hasOwn.call on objects from other frames.
- var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
- object[property] = method;
- method.displayName = property;
- // Set up a stack trace which can be used later to find what line of
- // code the original method was created on.
- method._stack = (new Error('Stack Trace for original')).stack;
-
- method.restore = function () {
- // For prototype properties try to reset by delete first.
- // If this fails (ex: localStorage on mobile safari) then force a reset
- // via direct assignment.
- if (!owned) {
- delete object[property];
- }
- if (object[property] === method) {
- object[property] = wrappedMethod;
- }
- };
-
- method.restore.sinon = true;
- mirrorProperties(method, wrappedMethod);
-
- return method;
- },
-
- extend: function extend(target) {
- for (var i = 1, l = arguments.length; i < l; i += 1) {
- for (var prop in arguments[i]) {
- if (arguments[i].hasOwnProperty(prop)) {
- target[prop] = arguments[i][prop];
- }
-
- // DONT ENUM bug, only care about toString
- if (arguments[i].hasOwnProperty("toString") &&
- arguments[i].toString != target.toString) {
- target.toString = arguments[i].toString;
- }
- }
- }
-
- return target;
- },
-
- create: function create(proto) {
- var F = function () {};
- F.prototype = proto;
- return new F();
- },
-
- deepEqual: function deepEqual(a, b) {
- if (sinon.match && sinon.match.isMatcher(a)) {
- return a.test(b);
- }
-
- if (typeof a != 'object' || typeof b != 'object') {
- if (isReallyNaN(a) && isReallyNaN(b)) {
- return true;
- } else {
- return a === b;
- }
- }
-
- if (isElement(a) || isElement(b)) {
- return a === b;
- }
-
- if (a === b) {
- return true;
- }
-
- if ((a === null && b !== null) || (a !== null && b === null)) {
- return false;
- }
-
- if (a instanceof RegExp && b instanceof RegExp) {
- return (a.source === b.source) && (a.global === b.global) &&
- (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
- }
-
- var aString = Object.prototype.toString.call(a);
- if (aString != Object.prototype.toString.call(b)) {
- return false;
- }
-
- if (aString == "[object Date]") {
- return a.valueOf() === b.valueOf();
- }
-
- var prop, aLength = 0, bLength = 0;
-
- if (aString == "[object Array]" && a.length !== b.length) {
- return false;
- }
-
- for (prop in a) {
- aLength += 1;
-
- if (!(prop in b)) {
- return false;
- }
-
- if (!deepEqual(a[prop], b[prop])) {
- return false;
- }
- }
-
- for (prop in b) {
- bLength += 1;
- }
-
- return aLength == bLength;
- },
-
- functionName: function functionName(func) {
- var name = func.displayName || func.name;
-
- // Use function decomposition as a last resort to get function
- // name. Does not rely on function decomposition to work - if it
- // doesn't debugging will be slightly less informative
- // (i.e. toString will say 'spy' rather than 'myFunc').
- if (!name) {
- var matches = func.toString().match(/function ([^\s\(]+)/);
- name = matches && matches[1];
- }
-
- return name;
- },
-
- functionToString: function toString() {
- if (this.getCall && this.callCount) {
- var thisValue, prop, i = this.callCount;
-
- while (i--) {
- thisValue = this.getCall(i).thisValue;
-
- for (prop in thisValue) {
- if (thisValue[prop] === this) {
- return prop;
- }
- }
- }
- }
-
- return this.displayName || "sinon fake";
- },
-
- getConfig: function (custom) {
- var config = {};
- custom = custom || {};
- var defaults = sinon.defaultConfig;
-
- for (var prop in defaults) {
- if (defaults.hasOwnProperty(prop)) {
- config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
- }
- }
-
- return config;
- },
-
- format: function (val) {
- return "" + val;
- },
-
- defaultConfig: {
- injectIntoThis: true,
- injectInto: null,
- properties: ["spy", "stub", "mock", "clock", "server", "requests"],
- useFakeTimers: true,
- useFakeServer: true
- },
-
- timesInWords: function timesInWords(count) {
- return count == 1 && "once" ||
- count == 2 && "twice" ||
- count == 3 && "thrice" ||
- (count || 0) + " times";
- },
-
- calledInOrder: function (spies) {
- for (var i = 1, l = spies.length; i < l; i++) {
- if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
- return false;
- }
- }
-
- return true;
- },
-
- orderByFirstCall: function (spies) {
- return spies.sort(function (a, b) {
- // uuid, won't ever be equal
- var aCall = a.getCall(0);
- var bCall = b.getCall(0);
- var aId = aCall && aCall.callId || -1;
- var bId = bCall && bCall.callId || -1;
-
- return aId < bId ? -1 : 1;
- });
- },
-
- log: function () {},
-
- logError: function (label, err) {
- var msg = label + " threw exception: ";
- sinon.log(msg + "[" + err.name + "] " + err.message);
- if (err.stack) { sinon.log(err.stack); }
-
- setTimeout(function () {
- err.message = msg + err.message;
- throw err;
- }, 0);
- },
-
- typeOf: function (value) {
- if (value === null) {
- return "null";
- }
- else if (value === undefined) {
- return "undefined";
- }
- var string = Object.prototype.toString.call(value);
- return string.substring(8, string.length - 1).toLowerCase();
- },
-
- createStubInstance: function (constructor) {
- if (typeof constructor !== "function") {
- throw new TypeError("The constructor should be a function.");
- }
- return sinon.stub(sinon.create(constructor.prototype));
- },
-
- restore: function (object) {
- if (object !== null && typeof object === "object") {
- for (var prop in object) {
- if (isRestorable(object[prop])) {
- object[prop].restore();
- }
- }
- }
- else if (isRestorable(object)) {
- object.restore();
- }
- }
- };
-
- var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
- var isAMD = typeof define === 'function' && typeof define.amd === 'object' && define.amd;
-
- function makePublicAPI(require, exports, module) {
- module.exports = sinon;
- sinon.spy = require("./sinon/spy");
- sinon.spyCall = require("./sinon/call");
- sinon.behavior = require("./sinon/behavior");
- sinon.stub = require("./sinon/stub");
- sinon.mock = require("./sinon/mock");
- sinon.collection = require("./sinon/collection");
- sinon.assert = require("./sinon/assert");
- sinon.sandbox = require("./sinon/sandbox");
- sinon.test = require("./sinon/test");
- sinon.testCase = require("./sinon/test_case");
- sinon.match = require("./sinon/match");
- }
-
- if (isAMD) {
- define(makePublicAPI);
- } else if (isNode) {
- try {
- formatio = require("formatio");
- } catch (e) {}
- makePublicAPI(require, exports, module);
- }
-
- if (formatio) {
- var formatter = formatio.configure({ quoteStrings: false });
- sinon.format = function () {
- return formatter.ascii.apply(formatter, arguments);
- };
- } else if (isNode) {
- try {
- var util = require("util");
- sinon.format = function (value) {
- return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
- };
- } catch (e) {
- /* Node, but no util module - would be very old, but better safe than
- sorry */
- }
- }
-
- return sinon;
-}(typeof formatio == "object" && formatio));
-
-/* @depend ../sinon.js */
-/*jslint eqeqeq: false, onevar: false, plusplus: false*/
-/*global module, require, sinon*/
-/**
- * Match functions
- *
- * @author Maximilian Antoni (mail@maxantoni.de)
- * @license BSD
- *
- * Copyright (c) 2012 Maximilian Antoni
- */
-
-(function (sinon) {
- var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
-
- if (!sinon && commonJSModule) {
- sinon = require("../sinon");
- }
-
- if (!sinon) {
- return;
- }
-
- function assertType(value, type, name) {
- var actual = sinon.typeOf(value);
- if (actual !== type) {
- throw new TypeError("Expected type of " + name + " to be " +
- type + ", but was " + actual);
- }
- }
-
- var matcher = {
- toString: function () {
- return this.message;
- }
- };
-
- function isMatcher(object) {
- return matcher.isPrototypeOf(object);
- }
-
- function matchObject(expectation, actual) {
- if (actual === null || actual === undefined) {
- return false;
- }
- for (var key in expectation) {
- if (expectation.hasOwnProperty(key)) {
- var exp = expectation[key];
- var act = actual[key];
- if (match.isMatcher(exp)) {
- if (!exp.test(act)) {
- return false;
- }
- } else if (sinon.typeOf(exp) === "object") {
- if (!matchObject(exp, act)) {
- return false;
- }
- } else if (!sinon.deepEqual(exp, act)) {
- return false;
- }
- }
- }
- return true;
- }
-
- matcher.or = function (m2) {
- if (!arguments.length) {
- throw new TypeError("Matcher expected");
- } else if (!isMatcher(m2)) {
- m2 = match(m2);
- }
- var m1 = this;
- var or = sinon.create(matcher);
- or.test = function (actual) {
- return m1.test(actual) || m2.test(actual);
- };
- or.message = m1.message + ".or(" + m2.message + ")";
- return or;
- };
-
- matcher.and = function (m2) {
- if (!arguments.length) {
- throw new TypeError("Matcher expected");
- } else if (!isMatcher(m2)) {
- m2 = match(m2);
- }
- var m1 = this;
- var and = sinon.create(matcher);
- and.test = function (actual) {
- return m1.test(actual) && m2.test(actual);
- };
- and.message = m1.message + ".and(" + m2.message + ")";
- return and;
- };
-
- var match = function (expectation, message) {
- var m = sinon.create(matcher);
- var type = sinon.typeOf(expectation);
- switch (type) {
- case "object":
- if (typeof expectation.test === "function") {
- m.test = function (actual) {
- return expectation.test(actual) === true;
- };
- m.message = "match(" + sinon.functionName(expectation.test) + ")";
- return m;
- }
- var str = [];
- for (var key in expectation) {
- if (expectation.hasOwnProperty(key)) {
- str.push(key + ": " + expectation[key]);
- }
- }
- m.test = function (actual) {
- return matchObject(expectation, actual);
- };
- m.message = "match(" + str.join(", ") + ")";
- break;
- case "number":
- m.test = function (actual) {
- return expectation == actual;
- };
- break;
- case "string":
- m.test = function (actual) {
- if (typeof actual !== "string") {
- return false;
- }
- return actual.indexOf(expectation) !== -1;
- };
- m.message = "match(\"" + expectation + "\")";
- break;
- case "regexp":
- m.test = function (actual) {
- if (typeof actual !== "string") {
- return false;
- }
- return expectation.test(actual);
- };
- break;
- case "function":
- m.test = expectation;
- if (message) {
- m.message = message;
- } else {
- m.message = "match(" + sinon.functionName(expectation) + ")";
- }
- break;
- default:
- m.test = function (actual) {
- return sinon.deepEqual(expectation, actual);
- };
- }
- if (!m.message) {
- m.message = "match(" + expectation + ")";
- }
- return m;
- };
-
- match.isMatcher = isMatcher;
-
- match.any = match(function () {
- return true;
- }, "any");
-
- match.defined = match(function (actual) {
- return actual !== null && actual !== undefined;
- }, "defined");
-
- match.truthy = match(function (actual) {
- return !!actual;
- }, "truthy");
-
- match.falsy = match(function (actual) {
- return !actual;
- }, "falsy");
-
- match.same = function (expectation) {
- return match(function (actual) {
- return expectation === actual;
- }, "same(" + expectation + ")");
- };
-
- match.typeOf = function (type) {
- assertType(type, "string", "type");
- return match(function (actual) {
- return sinon.typeOf(actual) === type;
- }, "typeOf(\"" + type + "\")");
- };
-
- match.instanceOf = function (type) {
- assertType(type, "function", "type");
- return match(function (actual) {
- return actual instanceof type;
- }, "instanceOf(" + sinon.functionName(type) + ")");
- };
-
- function createPropertyMatcher(propertyTest, messagePrefix) {
- return function (property, value) {
- assertType(property, "string", "property");
- var onlyProperty = arguments.length === 1;
- var message = messagePrefix + "(\"" + property + "\"";
- if (!onlyProperty) {
- message += ", " + value;
- }
- message += ")";
- return match(function (actual) {
- if (actual === undefined || actual === null ||
- !propertyTest(actual, property)) {
- return false;
- }
- return onlyProperty || sinon.deepEqual(value, actual[property]);
- }, message);
- };
- }
-
- match.has = createPropertyMatcher(function (actual, property) {
- if (typeof actual === "object") {
- return property in actual;
- }
- return actual[property] !== undefined;
- }, "has");
-
- match.hasOwn = createPropertyMatcher(function (actual, property) {
- return actual.hasOwnProperty(property);
- }, "hasOwn");
-
- match.bool = match.typeOf("boolean");
- match.number = match.typeOf("number");
- match.string = match.typeOf("string");
- match.object = match.typeOf("object");
- match.func = match.typeOf("function");
- match.array = match.typeOf("array");
- match.regexp = match.typeOf("regexp");
- match.date = match.typeOf("date");
-
- sinon.match = match;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = match; });
- } else if (commonJSModule) {
- module.exports = match;
- }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- * @depend match.js
- */
-/*jslint eqeqeq: false, onevar: false, plusplus: false*/
-/*global module, require, sinon*/
-/**
- * Spy calls
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @author Maximilian Antoni (mail@maxantoni.de)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- * Copyright (c) 2013 Maximilian Antoni
- */
-
-(function (sinon) {
- var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
- if (!sinon && commonJSModule) {
- sinon = require("../sinon");
- }
-
- if (!sinon) {
- return;
- }
-
- function throwYieldError(proxy, text, args) {
- var msg = sinon.functionName(proxy) + text;
- if (args.length) {
- msg += " Received [" + slice.call(args).join(", ") + "]";
- }
- throw new Error(msg);
- }
-
- var slice = Array.prototype.slice;
-
- var callProto = {
- calledOn: function calledOn(thisValue) {
- if (sinon.match && sinon.match.isMatcher(thisValue)) {
- return thisValue.test(this.thisValue);
- }
- return this.thisValue === thisValue;
- },
-
- calledWith: function calledWith() {
- for (var i = 0, l = arguments.length; i < l; i += 1) {
- if (!sinon.deepEqual(arguments[i], this.args[i])) {
- return false;
- }
- }
-
- return true;
- },
-
- calledWithMatch: function calledWithMatch() {
- for (var i = 0, l = arguments.length; i < l; i += 1) {
- var actual = this.args[i];
- var expectation = arguments[i];
- if (!sinon.match || !sinon.match(expectation).test(actual)) {
- return false;
- }
- }
- return true;
- },
-
- calledWithExactly: function calledWithExactly() {
- return arguments.length == this.args.length &&
- this.calledWith.apply(this, arguments);
- },
-
- notCalledWith: function notCalledWith() {
- return !this.calledWith.apply(this, arguments);
- },
-
- notCalledWithMatch: function notCalledWithMatch() {
- return !this.calledWithMatch.apply(this, arguments);
- },
-
- returned: function returned(value) {
- return sinon.deepEqual(value, this.returnValue);
- },
-
- threw: function threw(error) {
- if (typeof error === "undefined" || !this.exception) {
- return !!this.exception;
- }
-
- return this.exception === error || this.exception.name === error;
- },
-
- calledWithNew: function calledWithNew() {
- return this.proxy.prototype && this.thisValue instanceof this.proxy;
- },
-
- calledBefore: function (other) {
- return this.callId < other.callId;
- },
-
- calledAfter: function (other) {
- return this.callId > other.callId;
- },
-
- callArg: function (pos) {
- this.args[pos]();
- },
-
- callArgOn: function (pos, thisValue) {
- this.args[pos].apply(thisValue);
- },
-
- callArgWith: function (pos) {
- this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
- },
-
- callArgOnWith: function (pos, thisValue) {
- var args = slice.call(arguments, 2);
- this.args[pos].apply(thisValue, args);
- },
-
- "yield": function () {
- this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
- },
-
- yieldOn: function (thisValue) {
- var args = this.args;
- for (var i = 0, l = args.length; i < l; ++i) {
- if (typeof args[i] === "function") {
- args[i].apply(thisValue, slice.call(arguments, 1));
- return;
- }
- }
- throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
- },
-
- yieldTo: function (prop) {
- this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
- },
-
- yieldToOn: function (prop, thisValue) {
- var args = this.args;
- for (var i = 0, l = args.length; i < l; ++i) {
- if (args[i] && typeof args[i][prop] === "function") {
- args[i][prop].apply(thisValue, slice.call(arguments, 2));
- return;
- }
- }
- throwYieldError(this.proxy, " cannot yield to '" + prop +
- "' since no callback was passed.", args);
- },
-
- toString: function () {
- var callStr = this.proxy.toString() + "(";
- var args = [];
-
- for (var i = 0, l = this.args.length; i < l; ++i) {
- args.push(sinon.format(this.args[i]));
- }
-
- callStr = callStr + args.join(", ") + ")";
-
- if (typeof this.returnValue != "undefined") {
- callStr += " => " + sinon.format(this.returnValue);
- }
-
- if (this.exception) {
- callStr += " !" + this.exception.name;
-
- if (this.exception.message) {
- callStr += "(" + this.exception.message + ")";
- }
- }
-
- return callStr;
- }
- };
-
- callProto.invokeCallback = callProto.yield;
-
- function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
- if (typeof id !== "number") {
- throw new TypeError("Call id is not a number");
- }
- var proxyCall = sinon.create(callProto);
- proxyCall.proxy = spy;
- proxyCall.thisValue = thisValue;
- proxyCall.args = args;
- proxyCall.returnValue = returnValue;
- proxyCall.exception = exception;
- proxyCall.callId = id;
-
- return proxyCall;
- }
- createSpyCall.toString = callProto.toString; // used by mocks
-
- sinon.spyCall = createSpyCall;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = createSpyCall; });
- } else if (commonJSModule) {
- module.exports = createSpyCall;
- }
-}(typeof sinon == "object" && sinon || null));
-
-
-/**
- * @depend ../sinon.js
- * @depend call.js
- */
-/*jslint eqeqeq: false, onevar: false, plusplus: false*/
-/*global module, require, sinon*/
-/**
- * Spy functions
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
- var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
- var push = Array.prototype.push;
- var slice = Array.prototype.slice;
- var callId = 0;
-
- if (!sinon && commonJSModule) {
- sinon = require("../sinon");
- }
-
- if (!sinon) {
- return;
- }
-
- function spy(object, property) {
- if (!property && typeof object == "function") {
- return spy.create(object);
- }
-
- if (!object && !property) {
- return spy.create(function () { });
- }
-
- var method = object[property];
- return sinon.wrapMethod(object, property, spy.create(method));
- }
-
- function matchingFake(fakes, args, strict) {
- if (!fakes) {
- return;
- }
-
- for (var i = 0, l = fakes.length; i < l; i++) {
- if (fakes[i].matches(args, strict)) {
- return fakes[i];
- }
- }
- }
-
- function incrementCallCount() {
- this.called = true;
- this.callCount += 1;
- this.notCalled = false;
- this.calledOnce = this.callCount == 1;
- this.calledTwice = this.callCount == 2;
- this.calledThrice = this.callCount == 3;
- }
-
- function createCallProperties() {
- this.firstCall = this.getCall(0);
- this.secondCall = this.getCall(1);
- this.thirdCall = this.getCall(2);
- this.lastCall = this.getCall(this.callCount - 1);
- }
-
- var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
- function createProxy(func) {
- // Retain the function length:
- var p;
- if (func.length) {
- eval("p = (function proxy(" + vars.substring(0, func.length * 2 - 1) +
- ") { return p.invoke(func, this, slice.call(arguments)); });");
- }
- else {
- p = function proxy() {
- return p.invoke(func, this, slice.call(arguments));
- };
- }
- return p;
- }
-
- var uuid = 0;
-
- // Public API
- var spyApi = {
- reset: function () {
- this.called = false;
- this.notCalled = true;
- this.calledOnce = false;
- this.calledTwice = false;
- this.calledThrice = false;
- this.callCount = 0;
- this.firstCall = null;
- this.secondCall = null;
- this.thirdCall = null;
- this.lastCall = null;
- this.args = [];
- this.returnValues = [];
- this.thisValues = [];
- this.exceptions = [];
- this.callIds = [];
- if (this.fakes) {
- for (var i = 0; i < this.fakes.length; i++) {
- this.fakes[i].reset();
- }
- }
- },
-
- create: function create(func) {
- var name;
-
- if (typeof func != "function") {
- func = function () { };
- } else {
- name = sinon.functionName(func);
- }
-
- var proxy = createProxy(func);
-
- sinon.extend(proxy, spy);
- delete proxy.create;
- sinon.extend(proxy, func);
-
- proxy.reset();
- proxy.prototype = func.prototype;
- proxy.displayName = name || "spy";
- proxy.toString = sinon.functionToString;
- proxy._create = sinon.spy.create;
- proxy.id = "spy#" + uuid++;
-
- return proxy;
- },
-
- invoke: function invoke(func, thisValue, args) {
- var matching = matchingFake(this.fakes, args);
- var exception, returnValue;
-
- incrementCallCount.call(this);
- push.call(this.thisValues, thisValue);
- push.call(this.args, args);
- push.call(this.callIds, callId++);
-
- // Make call properties available from within the spied function:
- createCallProperties.call(this);
-
- try {
- if (matching) {
- returnValue = matching.invoke(func, thisValue, args);
- } else {
- returnValue = (this.func || func).apply(thisValue, args);
- }
-
- var thisCall = this.getCall(this.callCount - 1);
- if (thisCall.calledWithNew() && typeof returnValue !== 'object') {
- returnValue = thisValue;
- }
- } catch (e) {
- exception = e;
- }
-
- push.call(this.exceptions, exception);
- push.call(this.returnValues, returnValue);
-
- // Make return value and exception available in the calls:
- createCallProperties.call(this);
-
- if (exception !== undefined) {
- throw exception;
- }
-
- return returnValue;
- },
-
- named: function named(name) {
- this.displayName = name;
- return this;
- },
-
- getCall: function getCall(i) {
- if (i < 0 || i >= this.callCount) {
- return null;
- }
-
- return sinon.spyCall(this, this.thisValues[i], this.args[i],
- this.returnValues[i], this.exceptions[i],
- this.callIds[i]);
- },
-
- getCalls: function () {
- var calls = [];
- var i;
-
- for (i = 0; i < this.callCount; i++) {
- calls.push(this.getCall(i));
- }
-
- return calls;
- },
-
- calledBefore: function calledBefore(spyFn) {
- if (!this.called) {
- return false;
- }
-
- if (!spyFn.called) {
- return true;
- }
-
- return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
- },
-
- calledAfter: function calledAfter(spyFn) {
- if (!this.called || !spyFn.called) {
- return false;
- }
-
- return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
- },
-
- withArgs: function () {
- var args = slice.call(arguments);
-
- if (this.fakes) {
- var match = matchingFake(this.fakes, args, true);
-
- if (match) {
- return match;
- }
- } else {
- this.fakes = [];
- }
-
- var original = this;
- var fake = this._create();
- fake.matchingAguments = args;
- fake.parent = this;
- push.call(this.fakes, fake);
-
- fake.withArgs = function () {
- return original.withArgs.apply(original, arguments);
- };
-
- for (var i = 0; i < this.args.length; i++) {
- if (fake.matches(this.args[i])) {
- incrementCallCount.call(fake);
- push.call(fake.thisValues, this.thisValues[i]);
- push.call(fake.args, this.args[i]);
- push.call(fake.returnValues, this.returnValues[i]);
- push.call(fake.exceptions, this.exceptions[i]);
- push.call(fake.callIds, this.callIds[i]);
- }
- }
- createCallProperties.call(fake);
-
- return fake;
- },
-
- matches: function (args, strict) {
- var margs = this.matchingAguments;
-
- if (margs.length <= args.length &&
- sinon.deepEqual(margs, args.slice(0, margs.length))) {
- return !strict || margs.length == args.length;
- }
- },
-
- printf: function (format) {
- var spy = this;
- var args = slice.call(arguments, 1);
- var formatter;
-
- return (format || "").replace(/%(.)/g, function (match, specifyer) {
- formatter = spyApi.formatters[specifyer];
-
- if (typeof formatter == "function") {
- return formatter.call(null, spy, args);
- } else if (!isNaN(parseInt(specifyer, 10))) {
- return sinon.format(args[specifyer - 1]);
- }
-
- return "%" + specifyer;
- });
- }
- };
-
- function delegateToCalls(method, matchAny, actual, notCalled) {
- spyApi[method] = function () {
- if (!this.called) {
- if (notCalled) {
- return notCalled.apply(this, arguments);
- }
- return false;
- }
-
- var currentCall;
- var matches = 0;
-
- for (var i = 0, l = this.callCount; i < l; i += 1) {
- currentCall = this.getCall(i);
-
- if (currentCall[actual || method].apply(currentCall, arguments)) {
- matches += 1;
-
- if (matchAny) {
- return true;
- }
- }
- }
-
- return matches === this.callCount;
- };
- }
-
- delegateToCalls("calledOn", true);
- delegateToCalls("alwaysCalledOn", false, "calledOn");
- delegateToCalls("calledWith", true);
- delegateToCalls("calledWithMatch", true);
- delegateToCalls("alwaysCalledWith", false, "calledWith");
- delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
- delegateToCalls("calledWithExactly", true);
- delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
- delegateToCalls("neverCalledWith", false, "notCalledWith",
- function () { return true; });
- delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch",
- function () { return true; });
- delegateToCalls("threw", true);
- delegateToCalls("alwaysThrew", false, "threw");
- delegateToCalls("returned", true);
- delegateToCalls("alwaysReturned", false, "returned");
- delegateToCalls("calledWithNew", true);
- delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
- delegateToCalls("callArg", false, "callArgWith", function () {
- throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
- });
- spyApi.callArgWith = spyApi.callArg;
- delegateToCalls("callArgOn", false, "callArgOnWith", function () {
- throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
- });
- spyApi.callArgOnWith = spyApi.callArgOn;
- delegateToCalls("yield", false, "yield", function () {
- throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
- });
- // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
- spyApi.invokeCallback = spyApi.yield;
- delegateToCalls("yieldOn", false, "yieldOn", function () {
- throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
- });
- delegateToCalls("yieldTo", false, "yieldTo", function (property) {
- throw new Error(this.toString() + " cannot yield to '" + property +
- "' since it was not yet invoked.");
- });
- delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
- throw new Error(this.toString() + " cannot yield to '" + property +
- "' since it was not yet invoked.");
- });
-
- spyApi.formatters = {
- "c": function (spy) {
- return sinon.timesInWords(spy.callCount);
- },
-
- "n": function (spy) {
- return spy.toString();
- },
-
- "C": function (spy) {
- var calls = [];
-
- for (var i = 0, l = spy.callCount; i < l; ++i) {
- var stringifiedCall = " " + spy.getCall(i).toString();
- if (/\n/.test(calls[i - 1])) {
- stringifiedCall = "\n" + stringifiedCall;
- }
- push.call(calls, stringifiedCall);
- }
-
- return calls.length > 0 ? "\n" + calls.join("\n") : "";
- },
-
- "t": function (spy) {
- var objects = [];
-
- for (var i = 0, l = spy.callCount; i < l; ++i) {
- push.call(objects, sinon.format(spy.thisValues[i]));
- }
-
- return objects.join(", ");
- },
-
- "*": function (spy, args) {
- var formatted = [];
-
- for (var i = 0, l = args.length; i < l; ++i) {
- push.call(formatted, sinon.format(args[i]));
- }
-
- return formatted.join(", ");
- }
- };
-
- sinon.extend(spy, spyApi);
-
- spy.spyCall = sinon.spyCall;
- sinon.spy = spy;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = spy; });
- } else if (commonJSModule) {
- module.exports = spy;
- }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- */
-/*jslint eqeqeq: false, onevar: false*/
-/*global module, require, sinon, process, setImmediate, setTimeout*/
-/**
- * Stub behavior
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @author Tim Fischbach (mail@timfischbach.de)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
- var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
-
- if (!sinon && commonJSModule) {
- sinon = require("../sinon");
- }
-
- if (!sinon) {
- return;
- }
-
- var slice = Array.prototype.slice;
- var join = Array.prototype.join;
- var proto;
-
- var nextTick = (function () {
- if (typeof process === "object" && typeof process.nextTick === "function") {
- return process.nextTick;
- } else if (typeof setImmediate === "function") {
- return setImmediate;
- } else {
- return function (callback) {
- setTimeout(callback, 0);
- };
- }
- })();
-
- function throwsException(error, message) {
- if (typeof error == "string") {
- this.exception = new Error(message || "");
- this.exception.name = error;
- } else if (!error) {
- this.exception = new Error("Error");
- } else {
- this.exception = error;
- }
-
- return this;
- }
-
- function getCallback(behavior, args) {
- var callArgAt = behavior.callArgAt;
-
- if (callArgAt < 0) {
- var callArgProp = behavior.callArgProp;
-
- for (var i = 0, l = args.length; i < l; ++i) {
- if (!callArgProp && typeof args[i] == "function") {
- return args[i];
- }
-
- if (callArgProp && args[i] &&
- typeof args[i][callArgProp] == "function") {
- return args[i][callArgProp];
- }
- }
-
- return null;
- }
-
- return args[callArgAt];
- }
-
- function getCallbackError(behavior, func, args) {
- if (behavior.callArgAt < 0) {
- var msg;
-
- if (behavior.callArgProp) {
- msg = sinon.functionName(behavior.stub) +
- " expected to yield to '" + behavior.callArgProp +
- "', but no object with such a property was passed.";
- } else {
- msg = sinon.functionName(behavior.stub) +
- " expected to yield, but no callback was passed.";
- }
-
- if (args.length > 0) {
- msg += " Received [" + join.call(args, ", ") + "]";
- }
-
- return msg;
- }
-
- return "argument at index " + behavior.callArgAt + " is not a function: " + func;
- }
-
- function callCallback(behavior, args) {
- if (typeof behavior.callArgAt == "number") {
- var func = getCallback(behavior, args);
-
- if (typeof func != "function") {
- throw new TypeError(getCallbackError(behavior, func, args));
- }
-
- if (behavior.callbackAsync) {
- nextTick(function() {
- func.apply(behavior.callbackContext, behavior.callbackArguments);
- });
- } else {
- func.apply(behavior.callbackContext, behavior.callbackArguments);
- }
- }
- }
-
- proto = {
- create: function(stub) {
- var behavior = sinon.extend({}, sinon.behavior);
- delete behavior.create;
- behavior.stub = stub;
-
- return behavior;
- },
-
- isPresent: function() {
- return (typeof this.callArgAt == 'number' ||
- this.exception ||
- typeof this.returnArgAt == 'number' ||
- this.returnThis ||
- this.returnValueDefined);
- },
-
- invoke: function(context, args) {
- callCallback(this, args);
-
- if (this.exception) {
- throw this.exception;
- } else if (typeof this.returnArgAt == 'number') {
- return args[this.returnArgAt];
- } else if (this.returnThis) {
- return context;
- }
-
- return this.returnValue;
- },
-
- onCall: function(index) {
- return this.stub.onCall(index);
- },
-
- onFirstCall: function() {
- return this.stub.onFirstCall();
- },
-
- onSecondCall: function() {
- return this.stub.onSecondCall();
- },
-
- onThirdCall: function() {
- return this.stub.onThirdCall();
- },
-
- withArgs: function(/* arguments */) {
- throw new Error('Defining a stub by invoking "stub.onCall(...).withArgs(...)" is not supported. ' +
- 'Use "stub.withArgs(...).onCall(...)" to define sequential behavior for calls with certain arguments.');
- },
-
- callsArg: function callsArg(pos) {
- if (typeof pos != "number") {
- throw new TypeError("argument index is not number");
- }
-
- this.callArgAt = pos;
- this.callbackArguments = [];
- this.callbackContext = undefined;
- this.callArgProp = undefined;
- this.callbackAsync = false;
-
- return this;
- },
-
- callsArgOn: function callsArgOn(pos, context) {
- if (typeof pos != "number") {
- throw new TypeError("argument index is not number");
- }
- if (typeof context != "object") {
- throw new TypeError("argument context is not an object");
- }
-
- this.callArgAt = pos;
- this.callbackArguments = [];
- this.callbackContext = context;
- this.callArgProp = undefined;
- this.callbackAsync = false;
-
- return this;
- },
-
- callsArgWith: function callsArgWith(pos) {
- if (typeof pos != "number") {
- throw new TypeError("argument index is not number");
- }
-
- this.callArgAt = pos;
- this.callbackArguments = slice.call(arguments, 1);
- this.callbackContext = undefined;
- this.callArgProp = undefined;
- this.callbackAsync = false;
-
- return this;
- },
-
- callsArgOnWith: function callsArgWith(pos, context) {
- if (typeof pos != "number") {
- throw new TypeError("argument index is not number");
- }
- if (typeof context != "object") {
- throw new TypeError("argument context is not an object");
- }
-
- this.callArgAt = pos;
- this.callbackArguments = slice.call(arguments, 2);
- this.callbackContext = context;
- this.callArgProp = undefined;
- this.callbackAsync = false;
-
- return this;
- },
-
- yields: function () {
- this.callArgAt = -1;
- this.callbackArguments = slice.call(arguments, 0);
- this.callbackContext = undefined;
- this.callArgProp = undefined;
- this.callbackAsync = false;
-
- return this;
- },
-
- yieldsOn: function (context) {
- if (typeof context != "object") {
- throw new TypeError("argument context is not an object");
- }
-
- this.callArgAt = -1;
- this.callbackArguments = slice.call(arguments, 1);
- this.callbackContext = context;
- this.callArgProp = undefined;
- this.callbackAsync = false;
-
- return this;
- },
-
- yieldsTo: function (prop) {
- this.callArgAt = -1;
- this.callbackArguments = slice.call(arguments, 1);
- this.callbackContext = undefined;
- this.callArgProp = prop;
- this.callbackAsync = false;
-
- return this;
- },
-
- yieldsToOn: function (prop, context) {
- if (typeof context != "object") {
- throw new TypeError("argument context is not an object");
- }
-
- this.callArgAt = -1;
- this.callbackArguments = slice.call(arguments, 2);
- this.callbackContext = context;
- this.callArgProp = prop;
- this.callbackAsync = false;
-
- return this;
- },
-
-
- "throws": throwsException,
- throwsException: throwsException,
-
- returns: function returns(value) {
- this.returnValue = value;
- this.returnValueDefined = true;
-
- return this;
- },
-
- returnsArg: function returnsArg(pos) {
- if (typeof pos != "number") {
- throw new TypeError("argument index is not number");
- }
-
- this.returnArgAt = pos;
-
- return this;
- },
-
- returnsThis: function returnsThis() {
- this.returnThis = true;
-
- return this;
- }
- };
-
- // create asynchronous versions of callsArg* and yields* methods
- for (var method in proto) {
- // need to avoid creating anotherasync versions of the newly added async methods
- if (proto.hasOwnProperty(method) &&
- method.match(/^(callsArg|yields)/) &&
- !method.match(/Async/)) {
- proto[method + 'Async'] = (function (syncFnName) {
- return function () {
- var result = this[syncFnName].apply(this, arguments);
- this.callbackAsync = true;
- return result;
- };
- })(method);
- }
- }
-
- sinon.behavior = proto;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = proto; });
- } else if (commonJSModule) {
- module.exports = proto;
- }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- * @depend spy.js
- * @depend behavior.js
- */
-/*jslint eqeqeq: false, onevar: false*/
-/*global module, require, sinon*/
-/**
- * Stub functions
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
- var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
-
- if (!sinon && commonJSModule) {
- sinon = require("../sinon");
- }
-
- if (!sinon) {
- return;
- }
-
- function stub(object, property, func) {
- if (!!func && typeof func != "function") {
- throw new TypeError("Custom stub should be function");
- }
-
- var wrapper;
-
- if (func) {
- wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
- } else {
- wrapper = stub.create();
- }
-
- if (!object && typeof property === "undefined") {
- return sinon.stub.create();
- }
-
- if (typeof property === "undefined" && typeof object == "object") {
- for (var prop in object) {
- if (typeof object[prop] === "function") {
- stub(object, prop);
- }
- }
-
- return object;
- }
-
- return sinon.wrapMethod(object, property, wrapper);
- }
-
- function getDefaultBehavior(stub) {
- return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
- }
-
- function getParentBehaviour(stub) {
- return (stub.parent && getCurrentBehavior(stub.parent));
- }
-
- function getCurrentBehavior(stub) {
- var behavior = stub.behaviors[stub.callCount - 1];
- return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
- }
-
- var uuid = 0;
-
- sinon.extend(stub, (function () {
- var proto = {
- create: function create() {
- var functionStub = function () {
- return getCurrentBehavior(functionStub).invoke(this, arguments);
- };
-
- functionStub.id = "stub#" + uuid++;
- var orig = functionStub;
- functionStub = sinon.spy.create(functionStub);
- functionStub.func = orig;
-
- sinon.extend(functionStub, stub);
- functionStub._create = sinon.stub.create;
- functionStub.displayName = "stub";
- functionStub.toString = sinon.functionToString;
-
- functionStub.defaultBehavior = null;
- functionStub.behaviors = [];
-
- return functionStub;
- },
-
- resetBehavior: function () {
- var i;
-
- this.defaultBehavior = null;
- this.behaviors = [];
-
- delete this.returnValue;
- delete this.returnArgAt;
- this.returnThis = false;
-
- if (this.fakes) {
- for (i = 0; i < this.fakes.length; i++) {
- this.fakes[i].resetBehavior();
- }
- }
- },
-
- onCall: function(index) {
- if (!this.behaviors[index]) {
- this.behaviors[index] = sinon.behavior.create(this);
- }
-
- return this.behaviors[index];
- },
-
- onFirstCall: function() {
- return this.onCall(0);
- },
-
- onSecondCall: function() {
- return this.onCall(1);
- },
-
- onThirdCall: function() {
- return this.onCall(2);
- }
- };
-
- for (var method in sinon.behavior) {
- if (sinon.behavior.hasOwnProperty(method) &&
- !proto.hasOwnProperty(method) &&
- method != 'create' &&
- method != 'withArgs' &&
- method != 'invoke') {
- proto[method] = (function(behaviorMethod) {
- return function() {
- this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
- this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
- return this;
- };
- }(method));
- }
- }
-
- return proto;
- }()));
-
- sinon.stub = stub;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = stub; });
- } else if (commonJSModule) {
- module.exports = stub;
- }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- * @depend stub.js
- */
-/*jslint eqeqeq: false, onevar: false, nomen: false*/
-/*global module, require, sinon*/
-/**
- * Mock functions.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
- var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
- var push = [].push;
- var match;
-
- if (!sinon && commonJSModule) {
- sinon = require("../sinon");
- }
-
- if (!sinon) {
- return;
- }
-
- match = sinon.match;
-
- if (!match && commonJSModule) {
- match = require("./match");
- }
-
- function mock(object) {
- if (!object) {
- return sinon.expectation.create("Anonymous mock");
- }
-
- return mock.create(object);
- }
-
- sinon.mock = mock;
-
- sinon.extend(mock, (function () {
- function each(collection, callback) {
- if (!collection) {
- return;
- }
-
- for (var i = 0, l = collection.length; i < l; i += 1) {
- callback(collection[i]);
- }
- }
-
- return {
- create: function create(object) {
- if (!object) {
- throw new TypeError("object is null");
- }
-
- var mockObject = sinon.extend({}, mock);
- mockObject.object = object;
- delete mockObject.create;
-
- return mockObject;
- },
-
- expects: function expects(method) {
- if (!method) {
- throw new TypeError("method is falsy");
- }
-
- if (!this.expectations) {
- this.expectations = {};
- this.proxies = [];
- }
-
- if (!this.expectations[method]) {
- this.expectations[method] = [];
- var mockObject = this;
-
- sinon.wrapMethod(this.object, method, function () {
- return mockObject.invokeMethod(method, this, arguments);
- });
-
- push.call(this.proxies, method);
- }
-
- var expectation = sinon.expectation.create(method);
- push.call(this.expectations[method], expectation);
-
- return expectation;
- },
-
- restore: function restore() {
- var object = this.object;
-
- each(this.proxies, function (proxy) {
- if (typeof object[proxy].restore == "function") {
- object[proxy].restore();
- }
- });
- },
-
- verify: function verify() {
- var expectations = this.expectations || {};
- var messages = [], met = [];
-
- each(this.proxies, function (proxy) {
- each(expectations[proxy], function (expectation) {
- if (!expectation.met()) {
- push.call(messages, expectation.toString());
- } else {
- push.call(met, expectation.toString());
- }
- });
- });
-
- this.restore();
-
- if (messages.length > 0) {
- sinon.expectation.fail(messages.concat(met).join("\n"));
- } else {
- sinon.expectation.pass(messages.concat(met).join("\n"));
- }
-
- return true;
- },
-
- invokeMethod: function invokeMethod(method, thisValue, args) {
- var expectations = this.expectations && this.expectations[method];
- var length = expectations && expectations.length || 0, i;
-
- for (i = 0; i < length; i += 1) {
- if (!expectations[i].met() &&
- expectations[i].allowsCall(thisValue, args)) {
- return expectations[i].apply(thisValue, args);
- }
- }
-
- var messages = [], available, exhausted = 0;
-
- for (i = 0; i < length; i += 1) {
- if (expectations[i].allowsCall(thisValue, args)) {
- available = available || expectations[i];
- } else {
- exhausted += 1;
- }
- push.call(messages, " " + expectations[i].toString());
- }
-
- if (exhausted === 0) {
- return available.apply(thisValue, args);
- }
-
- messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
- proxy: method,
- args: args
- }));
-
- sinon.expectation.fail(messages.join("\n"));
- }
- };
- }()));
-
- var times = sinon.timesInWords;
-
- sinon.expectation = (function () {
- var slice = Array.prototype.slice;
- var _invoke = sinon.spy.invoke;
-
- function callCountInWords(callCount) {
- if (callCount == 0) {
- return "never called";
- } else {
- return "called " + times(callCount);
- }
- }
-
- function expectedCallCountInWords(expectation) {
- var min = expectation.minCalls;
- var max = expectation.maxCalls;
-
- if (typeof min == "number" && typeof max == "number") {
- var str = times(min);
-
- if (min != max) {
- str = "at least " + str + " and at most " + times(max);
- }
-
- return str;
- }
-
- if (typeof min == "number") {
- return "at least " + times(min);
- }
-
- return "at most " + times(max);
- }
-
- function receivedMinCalls(expectation) {
- var hasMinLimit = typeof expectation.minCalls == "number";
- return !hasMinLimit || expectation.callCount >= expectation.minCalls;
- }
-
- function receivedMaxCalls(expectation) {
- if (typeof expectation.maxCalls != "number") {
- return false;
- }
-
- return expectation.callCount == expectation.maxCalls;
- }
-
- function verifyMatcher(possibleMatcher, arg){
- if (match && match.isMatcher(possibleMatcher)) {
- return possibleMatcher.test(arg);
- } else {
- return true;
- }
- }
-
- return {
- minCalls: 1,
- maxCalls: 1,
-
- create: function create(methodName) {
- var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
- delete expectation.create;
- expectation.method = methodName;
-
- return expectation;
- },
-
- invoke: function invoke(func, thisValue, args) {
- this.verifyCallAllowed(thisValue, args);
-
- return _invoke.apply(this, arguments);
- },
-
- atLeast: function atLeast(num) {
- if (typeof num != "number") {
- throw new TypeError("'" + num + "' is not number");
- }
-
- if (!this.limitsSet) {
- this.maxCalls = null;
- this.limitsSet = true;
- }
-
- this.minCalls = num;
-
- return this;
- },
-
- atMost: function atMost(num) {
- if (typeof num != "number") {
- throw new TypeError("'" + num + "' is not number");
- }
-
- if (!this.limitsSet) {
- this.minCalls = null;
- this.limitsSet = true;
- }
-
- this.maxCalls = num;
-
- return this;
- },
-
- never: function never() {
- return this.exactly(0);
- },
-
- once: function once() {
- return this.exactly(1);
- },
-
- twice: function twice() {
- return this.exactly(2);
- },
-
- thrice: function thrice() {
- return this.exactly(3);
- },
-
- exactly: function exactly(num) {
- if (typeof num != "number") {
- throw new TypeError("'" + num + "' is not a number");
- }
-
- this.atLeast(num);
- return this.atMost(num);
- },
-
- met: function met() {
- return !this.failed && receivedMinCalls(this);
- },
-
- verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
- if (receivedMaxCalls(this)) {
- this.failed = true;
- sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
- }
-
- if ("expectedThis" in this && this.expectedThis !== thisValue) {
- sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
- this.expectedThis);
- }
-
- if (!("expectedArguments" in this)) {
- return;
- }
-
- if (!args) {
- sinon.expectation.fail(this.method + " received no arguments, expected " +
- sinon.format(this.expectedArguments));
- }
-
- if (args.length < this.expectedArguments.length) {
- sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
- "), expected " + sinon.format(this.expectedArguments));
- }
-
- if (this.expectsExactArgCount &&
- args.length != this.expectedArguments.length) {
- sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
- "), expected " + sinon.format(this.expectedArguments));
- }
-
- for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
-
- if (!verifyMatcher(this.expectedArguments[i],args[i])) {
- sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
- ", didn't match " + this.expectedArguments.toString());
- }
-
- if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
- sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
- ", expected " + sinon.format(this.expectedArguments));
- }
- }
- },
-
- allowsCall: function allowsCall(thisValue, args) {
- if (this.met() && receivedMaxCalls(this)) {
- return false;
- }
-
- if ("expectedThis" in this && this.expectedThis !== thisValue) {
- return false;
- }
-
- if (!("expectedArguments" in this)) {
- return true;
- }
-
- args = args || [];
-
- if (args.length < this.expectedArguments.length) {
- return false;
- }
-
- if (this.expectsExactArgCount &&
- args.length != this.expectedArguments.length) {
- return false;
- }
-
- for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
- if (!verifyMatcher(this.expectedArguments[i],args[i])) {
- return false;
- }
-
- if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
- return false;
- }
- }
-
- return true;
- },
-
- withArgs: function withArgs() {
- this.expectedArguments = slice.call(arguments);
- return this;
- },
-
- withExactArgs: function withExactArgs() {
- this.withArgs.apply(this, arguments);
- this.expectsExactArgCount = true;
- return this;
- },
-
- on: function on(thisValue) {
- this.expectedThis = thisValue;
- return this;
- },
-
- toString: function () {
- var args = (this.expectedArguments || []).slice();
-
- if (!this.expectsExactArgCount) {
- push.call(args, "[...]");
- }
-
- var callStr = sinon.spyCall.toString.call({
- proxy: this.method || "anonymous mock expectation",
- args: args
- });
-
- var message = callStr.replace(", [...", "[, ...") + " " +
- expectedCallCountInWords(this);
-
- if (this.met()) {
- return "Expectation met: " + message;
- }
-
- return "Expected " + message + " (" +
- callCountInWords(this.callCount) + ")";
- },
-
- verify: function verify() {
- if (!this.met()) {
- sinon.expectation.fail(this.toString());
- } else {
- sinon.expectation.pass(this.toString());
- }
-
- return true;
- },
-
- pass: function(message) {
- sinon.assert.pass(message);
- },
- fail: function (message) {
- var exception = new Error(message);
- exception.name = "ExpectationError";
-
- throw exception;
- }
- };
- }());
-
- sinon.mock = mock;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = mock; });
- } else if (commonJSModule) {
- module.exports = mock;
- }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- * @depend stub.js
- * @depend mock.js
- */
-/*jslint eqeqeq: false, onevar: false, forin: true*/
-/*global module, require, sinon*/
-/**
- * Collections of stubs, spies and mocks.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
- var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
- var push = [].push;
- var hasOwnProperty = Object.prototype.hasOwnProperty;
-
- if (!sinon && commonJSModule) {
- sinon = require("../sinon");
- }
-
- if (!sinon) {
- return;
- }
-
- function getFakes(fakeCollection) {
- if (!fakeCollection.fakes) {
- fakeCollection.fakes = [];
- }
-
- return fakeCollection.fakes;
- }
-
- function each(fakeCollection, method) {
- var fakes = getFakes(fakeCollection);
-
- for (var i = 0, l = fakes.length; i < l; i += 1) {
- if (typeof fakes[i][method] == "function") {
- fakes[i][method]();
- }
- }
- }
-
- function compact(fakeCollection) {
- var fakes = getFakes(fakeCollection);
- var i = 0;
- while (i < fakes.length) {
- fakes.splice(i, 1);
- }
- }
-
- var collection = {
- verify: function resolve() {
- each(this, "verify");
- },
-
- restore: function restore() {
- each(this, "restore");
- compact(this);
- },
-
- verifyAndRestore: function verifyAndRestore() {
- var exception;
-
- try {
- this.verify();
- } catch (e) {
- exception = e;
- }
-
- this.restore();
-
- if (exception) {
- throw exception;
- }
- },
-
- add: function add(fake) {
- push.call(getFakes(this), fake);
- return fake;
- },
-
- spy: function spy() {
- return this.add(sinon.spy.apply(sinon, arguments));
- },
-
- stub: function stub(object, property, value) {
- if (property) {
- var original = object[property];
-
- if (typeof original != "function") {
- if (!hasOwnProperty.call(object, property)) {
- throw new TypeError("Cannot stub non-existent own property " + property);
- }
-
- object[property] = value;
-
- return this.add({
- restore: function () {
- object[property] = original;
- }
- });
- }
- }
- if (!property && !!object && typeof object == "object") {
- var stubbedObj = sinon.stub.apply(sinon, arguments);
-
- for (var prop in stubbedObj) {
- if (typeof stubbedObj[prop] === "function") {
- this.add(stubbedObj[prop]);
- }
- }
-
- return stubbedObj;
- }
-
- return this.add(sinon.stub.apply(sinon, arguments));
- },
-
- mock: function mock() {
- return this.add(sinon.mock.apply(sinon, arguments));
- },
-
- inject: function inject(obj) {
- var col = this;
-
- obj.spy = function () {
- return col.spy.apply(col, arguments);
- };
-
- obj.stub = function () {
- return col.stub.apply(col, arguments);
- };
-
- obj.mock = function () {
- return col.mock.apply(col, arguments);
- };
-
- return obj;
- }
- };
-
- sinon.collection = collection;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = collection; });
- } else if (commonJSModule) {
- module.exports = collection;
- }
-}(typeof sinon == "object" && sinon || null));
-
-/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
-/*global module, require, window*/
-/**
- * Fake timer API
- * setTimeout
- * setInterval
- * clearTimeout
- * clearInterval
- * tick
- * reset
- * Date
- *
- * Inspired by jsUnitMockTimeOut from JsUnit
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-if (typeof sinon == "undefined") {
- var sinon = {};
-}
-
-(function (global) {
- // node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
- // browsers, a number.
- // see https://github.com/cjohansen/Sinon.JS/pull/436
- var timeoutResult = setTimeout(function() {}, 0);
- var addTimerReturnsObject = typeof timeoutResult === 'object';
- clearTimeout(timeoutResult);
-
- var id = 1;
-
- function addTimer(args, recurring) {
- if (args.length === 0) {
- throw new Error("Function requires at least 1 parameter");
- }
-
- if (typeof args[0] === "undefined") {
- throw new Error("Callback must be provided to timer calls");
- }
-
- var toId = id++;
- var delay = args[1] || 0;
-
- if (!this.timeouts) {
- this.timeouts = {};
- }
-
- this.timeouts[toId] = {
- id: toId,
- func: args[0],
- callAt: this.now + delay,
- invokeArgs: Array.prototype.slice.call(args, 2)
- };
-
- if (recurring === true) {
- this.timeouts[toId].interval = delay;
- }
-
- if (addTimerReturnsObject) {
- return {
- id: toId,
- ref: function() {},
- unref: function() {}
- };
- }
- else {
- return toId;
- }
- }
-
- function parseTime(str) {
- if (!str) {
- return 0;
- }
-
- var strings = str.split(":");
- var l = strings.length, i = l;
- var ms = 0, parsed;
-
- if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
- throw new Error("tick only understands numbers and 'h:m:s'");
- }
-
- while (i--) {
- parsed = parseInt(strings[i], 10);
-
- if (parsed >= 60) {
- throw new Error("Invalid time " + str);
- }
-
- ms += parsed * Math.pow(60, (l - i - 1));
- }
-
- return ms * 1000;
- }
-
- function createObject(object) {
- var newObject;
-
- if (Object.create) {
- newObject = Object.create(object);
- } else {
- var F = function () {};
- F.prototype = object;
- newObject = new F();
- }
-
- newObject.Date.clock = newObject;
- return newObject;
- }
-
- sinon.clock = {
- now: 0,
-
- create: function create(now) {
- var clock = createObject(this);
-
- if (typeof now == "number") {
- clock.now = now;
- }
-
- if (!!now && typeof now == "object") {
- throw new TypeError("now should be milliseconds since UNIX epoch");
- }
-
- return clock;
- },
-
- setTimeout: function setTimeout(callback, timeout) {
- return addTimer.call(this, arguments, false);
- },
-
- clearTimeout: function clearTimeout(timerId) {
- if (!timerId) {
- // null appears to be allowed in most browsers, and appears to be relied upon by some libraries, like Bootstrap carousel
- return;
- }
- if (!this.timeouts) {
- this.timeouts = [];
- }
- // in Node, timerId is an object with .ref()/.unref(), and
- // its .id field is the actual timer id.
- if (typeof timerId === 'object') {
- timerId = timerId.id
- }
- if (timerId in this.timeouts) {
- delete this.timeouts[timerId];
- }
- },
-
- setInterval: function setInterval(callback, timeout) {
- return addTimer.call(this, arguments, true);
- },
-
- clearInterval: function clearInterval(timerId) {
- this.clearTimeout(timerId);
- },
-
- setImmediate: function setImmediate(callback) {
- var passThruArgs = Array.prototype.slice.call(arguments, 1);
-
- return addTimer.call(this, [callback, 0].concat(passThruArgs), false);
- },
-
- clearImmediate: function clearImmediate(timerId) {
- this.clearTimeout(timerId);
- },
-
- tick: function tick(ms) {
- ms = typeof ms == "number" ? ms : parseTime(ms);
- var tickFrom = this.now, tickTo = this.now + ms, previous = this.now;
- var timer = this.firstTimerInRange(tickFrom, tickTo);
-
- var firstException;
- while (timer && tickFrom <= tickTo) {
- if (this.timeouts[timer.id]) {
- tickFrom = this.now = timer.callAt;
- try {
- this.callTimer(timer);
- } catch (e) {
- firstException = firstException || e;
- }
- }
-
- timer = this.firstTimerInRange(previous, tickTo);
- previous = tickFrom;
- }
-
- this.now = tickTo;
-
- if (firstException) {
- throw firstException;
- }
-
- return this.now;
- },
-
- firstTimerInRange: function (from, to) {
- var timer, smallest = null, originalTimer;
-
- for (var id in this.timeouts) {
- if (this.timeouts.hasOwnProperty(id)) {
- if (this.timeouts[id].callAt < from || this.timeouts[id].callAt > to) {
- continue;
- }
-
- if (smallest === null || this.timeouts[id].callAt < smallest) {
- originalTimer = this.timeouts[id];
- smallest = this.timeouts[id].callAt;
-
- timer = {
- func: this.timeouts[id].func,
- callAt: this.timeouts[id].callAt,
- interval: this.timeouts[id].interval,
- id: this.timeouts[id].id,
- invokeArgs: this.timeouts[id].invokeArgs
- };
- }
- }
- }
-
- return timer || null;
- },
-
- callTimer: function (timer) {
- if (typeof timer.interval == "number") {
- this.timeouts[timer.id].callAt += timer.interval;
- } else {
- delete this.timeouts[timer.id];
- }
-
- try {
- if (typeof timer.func == "function") {
- timer.func.apply(null, timer.invokeArgs);
- } else {
- eval(timer.func);
- }
- } catch (e) {
- var exception = e;
- }
-
- if (!this.timeouts[timer.id]) {
- if (exception) {
- throw exception;
- }
- return;
- }
-
- if (exception) {
- throw exception;
- }
- },
-
- reset: function reset() {
- this.timeouts = {};
- },
-
- Date: (function () {
- var NativeDate = Date;
-
- function ClockDate(year, month, date, hour, minute, second, ms) {
- // Defensive and verbose to avoid potential harm in passing
- // explicit undefined when user does not pass argument
- switch (arguments.length) {
- case 0:
- return new NativeDate(ClockDate.clock.now);
- case 1:
- return new NativeDate(year);
- case 2:
- return new NativeDate(year, month);
- case 3:
- return new NativeDate(year, month, date);
- case 4:
- return new NativeDate(year, month, date, hour);
- case 5:
- return new NativeDate(year, month, date, hour, minute);
- case 6:
- return new NativeDate(year, month, date, hour, minute, second);
- default:
- return new NativeDate(year, month, date, hour, minute, second, ms);
- }
- }
-
- return mirrorDateProperties(ClockDate, NativeDate);
- }())
- };
-
- function mirrorDateProperties(target, source) {
- if (source.now) {
- target.now = function now() {
- return target.clock.now;
- };
- } else {
- delete target.now;
- }
-
- if (source.toSource) {
- target.toSource = function toSource() {
- return source.toSource();
- };
- } else {
- delete target.toSource;
- }
-
- target.toString = function toString() {
- return source.toString();
- };
-
- target.prototype = source.prototype;
- target.parse = source.parse;
- target.UTC = source.UTC;
- target.prototype.toUTCString = source.prototype.toUTCString;
-
- for (var prop in source) {
- if (source.hasOwnProperty(prop)) {
- target[prop] = source[prop];
- }
- }
-
- return target;
- }
-
- var methods = ["Date", "setTimeout", "setInterval",
- "clearTimeout", "clearInterval"];
-
- if (typeof global.setImmediate !== "undefined") {
- methods.push("setImmediate");
- }
-
- if (typeof global.clearImmediate !== "undefined") {
- methods.push("clearImmediate");
- }
-
- function restore() {
- var method;
-
- for (var i = 0, l = this.methods.length; i < l; i++) {
- method = this.methods[i];
-
- if (global[method].hadOwnProperty) {
- global[method] = this["_" + method];
- } else {
- try {
- delete global[method];
- } catch (e) {}
- }
- }
-
- // Prevent multiple executions which will completely remove these props
- this.methods = [];
- }
-
- function stubGlobal(method, clock) {
- clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(global, method);
- clock["_" + method] = global[method];
-
- if (method == "Date") {
- var date = mirrorDateProperties(clock[method], global[method]);
- global[method] = date;
- } else {
- global[method] = function () {
- return clock[method].apply(clock, arguments);
- };
-
- for (var prop in clock[method]) {
- if (clock[method].hasOwnProperty(prop)) {
- global[method][prop] = clock[method][prop];
- }
- }
- }
-
- global[method].clock = clock;
- }
-
- sinon.useFakeTimers = function useFakeTimers(now) {
- var clock = sinon.clock.create(now);
- clock.restore = restore;
- clock.methods = Array.prototype.slice.call(arguments,
- typeof now == "number" ? 1 : 0);
-
- if (clock.methods.length === 0) {
- clock.methods = methods;
- }
-
- for (var i = 0, l = clock.methods.length; i < l; i++) {
- stubGlobal(clock.methods[i], clock);
- }
-
- return clock;
- };
-}(typeof global != "undefined" && typeof global !== "function" ? global : this));
-
-sinon.timers = {
- setTimeout: setTimeout,
- clearTimeout: clearTimeout,
- setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
- clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
- setInterval: setInterval,
- clearInterval: clearInterval,
- Date: Date
-};
-
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = sinon;
-}
-
-/*jslint eqeqeq: false, onevar: false*/
-/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
-/**
- * Minimal Event interface implementation
- *
- * Original implementation by Sven Fuchs: https://gist.github.com/995028
- * Modifications and tests by Christian Johansen.
- *
- * @author Sven Fuchs (svenfuchs@artweb-design.de)
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2011 Sven Fuchs, Christian Johansen
- */
-
-if (typeof sinon == "undefined") {
- this.sinon = {};
-}
-
-(function () {
- var push = [].push;
-
- sinon.Event = function Event(type, bubbles, cancelable, target) {
- this.initEvent(type, bubbles, cancelable, target);
- };
-
- sinon.Event.prototype = {
- initEvent: function(type, bubbles, cancelable, target) {
- this.type = type;
- this.bubbles = bubbles;
- this.cancelable = cancelable;
- this.target = target;
- },
-
- stopPropagation: function () {},
-
- preventDefault: function () {
- this.defaultPrevented = true;
- }
- };
-
- sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
- this.initEvent(type, false, false, target);
- this.loaded = progressEventRaw.loaded || null;
- this.total = progressEventRaw.total || null;
- };
-
- sinon.ProgressEvent.prototype = new sinon.Event();
-
- sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent;
-
- sinon.CustomEvent = function CustomEvent(type, customData, target) {
- this.initEvent(type, false, false, target);
- this.detail = customData.detail || null;
- };
-
- sinon.CustomEvent.prototype = new sinon.Event();
-
- sinon.CustomEvent.prototype.constructor = sinon.CustomEvent;
-
- sinon.EventTarget = {
- addEventListener: function addEventListener(event, listener) {
- this.eventListeners = this.eventListeners || {};
- this.eventListeners[event] = this.eventListeners[event] || [];
- push.call(this.eventListeners[event], listener);
- },
-
- removeEventListener: function removeEventListener(event, listener) {
- var listeners = this.eventListeners && this.eventListeners[event] || [];
-
- for (var i = 0, l = listeners.length; i < l; ++i) {
- if (listeners[i] == listener) {
- return listeners.splice(i, 1);
- }
- }
- },
-
- dispatchEvent: function dispatchEvent(event) {
- var type = event.type;
- var listeners = this.eventListeners && this.eventListeners[type] || [];
-
- for (var i = 0; i < listeners.length; i++) {
- if (typeof listeners[i] == "function") {
- listeners[i].call(this, event);
- } else {
- listeners[i].handleEvent(event);
- }
- }
-
- return !!event.defaultPrevented;
- }
- };
-}());
-
-/**
- * @depend ../../sinon.js
- * @depend event.js
- */
-/*jslint eqeqeq: false, onevar: false*/
-/*global sinon, module, require, ActiveXObject, XMLHttpRequest, DOMParser*/
-/**
- * Fake XMLHttpRequest object
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-// wrapper for global
-(function(global) {
- if (typeof sinon === "undefined") {
- global.sinon = {};
- }
-
- var supportsProgress = typeof ProgressEvent !== "undefined";
- var supportsCustomEvent = typeof CustomEvent !== "undefined";
- sinon.xhr = { XMLHttpRequest: global.XMLHttpRequest };
- var xhr = sinon.xhr;
- xhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
- xhr.GlobalActiveXObject = global.ActiveXObject;
- xhr.supportsActiveX = typeof xhr.GlobalActiveXObject != "undefined";
- xhr.supportsXHR = typeof xhr.GlobalXMLHttpRequest != "undefined";
- xhr.workingXHR = xhr.supportsXHR ? xhr.GlobalXMLHttpRequest : xhr.supportsActiveX
- ? function() { return new xhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0") } : false;
- xhr.supportsCORS = xhr.supportsXHR && 'withCredentials' in (new sinon.xhr.GlobalXMLHttpRequest());
-
- /*jsl:ignore*/
- var unsafeHeaders = {
- "Accept-Charset": true,
- "Accept-Encoding": true,
- "Connection": true,
- "Content-Length": true,
- "Cookie": true,
- "Cookie2": true,
- "Content-Transfer-Encoding": true,
- "Date": true,
- "Expect": true,
- "Host": true,
- "Keep-Alive": true,
- "Referer": true,
- "TE": true,
- "Trailer": true,
- "Transfer-Encoding": true,
- "Upgrade": true,
- "User-Agent": true,
- "Via": true
- };
- /*jsl:end*/
-
- function FakeXMLHttpRequest() {
- this.readyState = FakeXMLHttpRequest.UNSENT;
- this.requestHeaders = {};
- this.requestBody = null;
- this.status = 0;
- this.statusText = "";
- this.upload = new UploadProgress();
- if (sinon.xhr.supportsCORS) {
- this.withCredentials = false;
- }
-
-
- var xhr = this;
- var events = ["loadstart", "load", "abort", "loadend"];
-
- function addEventListener(eventName) {
- xhr.addEventListener(eventName, function (event) {
- var listener = xhr["on" + eventName];
-
- if (listener && typeof listener == "function") {
- listener.call(this, event);
- }
- });
- }
-
- for (var i = events.length - 1; i >= 0; i--) {
- addEventListener(events[i]);
- }
-
- if (typeof FakeXMLHttpRequest.onCreate == "function") {
- FakeXMLHttpRequest.onCreate(this);
- }
- }
-
- // An upload object is created for each
- // FakeXMLHttpRequest and allows upload
- // events to be simulated using uploadProgress
- // and uploadError.
- function UploadProgress() {
- this.eventListeners = {
- "progress": [],
- "load": [],
- "abort": [],
- "error": []
- }
- }
-
- UploadProgress.prototype.addEventListener = function(event, listener) {
- this.eventListeners[event].push(listener);
- };
-
- UploadProgress.prototype.removeEventListener = function(event, listener) {
- var listeners = this.eventListeners[event] || [];
-
- for (var i = 0, l = listeners.length; i < l; ++i) {
- if (listeners[i] == listener) {
- return listeners.splice(i, 1);
- }
- }
- };
-
- UploadProgress.prototype.dispatchEvent = function(event) {
- var listeners = this.eventListeners[event.type] || [];
-
- for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
- listener(event);
- }
- };
-
- function verifyState(xhr) {
- if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
- throw new Error("INVALID_STATE_ERR");
- }
-
- if (xhr.sendFlag) {
- throw new Error("INVALID_STATE_ERR");
- }
- }
-
- // filtering to enable a white-list version of Sinon FakeXhr,
- // where whitelisted requests are passed through to real XHR
- function each(collection, callback) {
- if (!collection) return;
- for (var i = 0, l = collection.length; i < l; i += 1) {
- callback(collection[i]);
- }
- }
- function some(collection, callback) {
- for (var index = 0; index < collection.length; index++) {
- if(callback(collection[index]) === true) return true;
- }
- return false;
- }
- // largest arity in XHR is 5 - XHR#open
- var apply = function(obj,method,args) {
- switch(args.length) {
- case 0: return obj[method]();
- case 1: return obj[method](args[0]);
- case 2: return obj[method](args[0],args[1]);
- case 3: return obj[method](args[0],args[1],args[2]);
- case 4: return obj[method](args[0],args[1],args[2],args[3]);
- case 5: return obj[method](args[0],args[1],args[2],args[3],args[4]);
- }
- };
-
- FakeXMLHttpRequest.filters = [];
- FakeXMLHttpRequest.addFilter = function(fn) {
- this.filters.push(fn)
- };
- var IE6Re = /MSIE 6/;
- FakeXMLHttpRequest.defake = function(fakeXhr,xhrArgs) {
- var xhr = new sinon.xhr.workingXHR();
- each(["open","setRequestHeader","send","abort","getResponseHeader",
- "getAllResponseHeaders","addEventListener","overrideMimeType","removeEventListener"],
- function(method) {
- fakeXhr[method] = function() {
- return apply(xhr,method,arguments);
- };
- });
-
- var copyAttrs = function(args) {
- each(args, function(attr) {
- try {
- fakeXhr[attr] = xhr[attr]
- } catch(e) {
- if(!IE6Re.test(navigator.userAgent)) throw e;
- }
- });
- };
-
- var stateChange = function() {
- fakeXhr.readyState = xhr.readyState;
- if(xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
- copyAttrs(["status","statusText"]);
- }
- if(xhr.readyState >= FakeXMLHttpRequest.LOADING) {
- copyAttrs(["responseText"]);
- }
- if(xhr.readyState === FakeXMLHttpRequest.DONE) {
- copyAttrs(["responseXML"]);
- }
- if(fakeXhr.onreadystatechange) fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
- };
- if(xhr.addEventListener) {
- for(var event in fakeXhr.eventListeners) {
- if(fakeXhr.eventListeners.hasOwnProperty(event)) {
- each(fakeXhr.eventListeners[event],function(handler) {
- xhr.addEventListener(event, handler);
- });
- }
- }
- xhr.addEventListener("readystatechange",stateChange);
- } else {
- xhr.onreadystatechange = stateChange;
- }
- apply(xhr,"open",xhrArgs);
- };
- FakeXMLHttpRequest.useFilters = false;
-
- function verifyRequestOpened(xhr) {
- if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
- throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
- }
- }
-
- function verifyRequestSent(xhr) {
- if (xhr.readyState == FakeXMLHttpRequest.DONE) {
- throw new Error("Request done");
- }
- }
-
- function verifyHeadersReceived(xhr) {
- if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
- throw new Error("No headers received");
- }
- }
-
- function verifyResponseBodyType(body) {
- if (typeof body != "string") {
- var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
- body + ", which is not a string.");
- error.name = "InvalidBodyException";
- throw error;
- }
- }
-
- sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
- async: true,
-
- open: function open(method, url, async, username, password) {
- this.method = method;
- this.url = url;
- this.async = typeof async == "boolean" ? async : true;
- this.username = username;
- this.password = password;
- this.responseText = null;
- this.responseXML = null;
- this.requestHeaders = {};
- this.sendFlag = false;
- if(sinon.FakeXMLHttpRequest.useFilters === true) {
- var xhrArgs = arguments;
- var defake = some(FakeXMLHttpRequest.filters,function(filter) {
- return filter.apply(this,xhrArgs)
- });
- if (defake) {
- return sinon.FakeXMLHttpRequest.defake(this,arguments);
- }
- }
- this.readyStateChange(FakeXMLHttpRequest.OPENED);
- },
-
- readyStateChange: function readyStateChange(state) {
- this.readyState = state;
-
- if (typeof this.onreadystatechange == "function") {
- try {
- this.onreadystatechange();
- } catch (e) {
- sinon.logError("Fake XHR onreadystatechange handler", e);
- }
- }
-
- this.dispatchEvent(new sinon.Event("readystatechange"));
-
- switch (this.readyState) {
- case FakeXMLHttpRequest.DONE:
- this.dispatchEvent(new sinon.Event("load", false, false, this));
- this.dispatchEvent(new sinon.Event("loadend", false, false, this));
- this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
- if (supportsProgress) {
- this.upload.dispatchEvent(new sinon.ProgressEvent('progress', {loaded: 100, total: 100}));
- }
- break;
- }
- },
-
- setRequestHeader: function setRequestHeader(header, value) {
- verifyState(this);
-
- if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
- throw new Error("Refused to set unsafe header \"" + header + "\"");
- }
-
- if (this.requestHeaders[header]) {
- this.requestHeaders[header] += "," + value;
- } else {
- this.requestHeaders[header] = value;
- }
- },
-
- // Helps testing
- setResponseHeaders: function setResponseHeaders(headers) {
- verifyRequestOpened(this);
- this.responseHeaders = {};
-
- for (var header in headers) {
- if (headers.hasOwnProperty(header)) {
- this.responseHeaders[header] = headers[header];
- }
- }
-
- if (this.async) {
- this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
- } else {
- this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
- }
- },
-
- // Currently treats ALL data as a DOMString (i.e. no Document)
- send: function send(data) {
- verifyState(this);
-
- if (!/^(get|head)$/i.test(this.method)) {
- if (this.requestHeaders["Content-Type"]) {
- var value = this.requestHeaders["Content-Type"].split(";");
- this.requestHeaders["Content-Type"] = value[0] + ";charset=utf-8";
- } else {
- this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
- }
-
- this.requestBody = data;
- }
-
- this.errorFlag = false;
- this.sendFlag = this.async;
- this.readyStateChange(FakeXMLHttpRequest.OPENED);
-
- if (typeof this.onSend == "function") {
- this.onSend(this);
- }
-
- this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
- },
-
- abort: function abort() {
- this.aborted = true;
- this.responseText = null;
- this.errorFlag = true;
- this.requestHeaders = {};
-
- if (this.readyState > sinon.FakeXMLHttpRequest.UNSENT && this.sendFlag) {
- this.readyStateChange(sinon.FakeXMLHttpRequest.DONE);
- this.sendFlag = false;
- }
-
- this.readyState = sinon.FakeXMLHttpRequest.UNSENT;
-
- this.dispatchEvent(new sinon.Event("abort", false, false, this));
-
- this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
-
- if (typeof this.onerror === "function") {
- this.onerror();
- }
- },
-
- getResponseHeader: function getResponseHeader(header) {
- if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
- return null;
- }
-
- if (/^Set-Cookie2?$/i.test(header)) {
- return null;
- }
-
- header = header.toLowerCase();
-
- for (var h in this.responseHeaders) {
- if (h.toLowerCase() == header) {
- return this.responseHeaders[h];
- }
- }
-
- return null;
- },
-
- getAllResponseHeaders: function getAllResponseHeaders() {
- if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
- return "";
- }
-
- var headers = "";
-
- for (var header in this.responseHeaders) {
- if (this.responseHeaders.hasOwnProperty(header) &&
- !/^Set-Cookie2?$/i.test(header)) {
- headers += header + ": " + this.responseHeaders[header] + "\r\n";
- }
- }
-
- return headers;
- },
-
- setResponseBody: function setResponseBody(body) {
- verifyRequestSent(this);
- verifyHeadersReceived(this);
- verifyResponseBodyType(body);
-
- var chunkSize = this.chunkSize || 10;
- var index = 0;
- this.responseText = "";
-
- do {
- if (this.async) {
- this.readyStateChange(FakeXMLHttpRequest.LOADING);
- }
-
- this.responseText += body.substring(index, index + chunkSize);
- index += chunkSize;
- } while (index < body.length);
-
- var type = this.getResponseHeader("Content-Type");
-
- if (this.responseText &&
- (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
- try {
- this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
- } catch (e) {
- // Unable to parse XML - no biggie
- }
- }
-
- if (this.async) {
- this.readyStateChange(FakeXMLHttpRequest.DONE);
- } else {
- this.readyState = FakeXMLHttpRequest.DONE;
- }
- },
-
- respond: function respond(status, headers, body) {
- this.status = typeof status == "number" ? status : 200;
- this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
- this.setResponseHeaders(headers || {});
- this.setResponseBody(body || "");
- },
-
- uploadProgress: function uploadProgress(progressEventRaw) {
- if (supportsProgress) {
- this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
- }
- },
-
- uploadError: function uploadError(error) {
- if (supportsCustomEvent) {
- this.upload.dispatchEvent(new sinon.CustomEvent("error", {"detail": error}));
- }
- }
- });
-
- sinon.extend(FakeXMLHttpRequest, {
- UNSENT: 0,
- OPENED: 1,
- HEADERS_RECEIVED: 2,
- LOADING: 3,
- DONE: 4
- });
-
- // Borrowed from JSpec
- FakeXMLHttpRequest.parseXML = function parseXML(text) {
- var xmlDoc;
-
- if (typeof DOMParser != "undefined") {
- var parser = new DOMParser();
- xmlDoc = parser.parseFromString(text, "text/xml");
- } else {
- xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
- xmlDoc.async = "false";
- xmlDoc.loadXML(text);
- }
-
- return xmlDoc;
- };
-
- FakeXMLHttpRequest.statusCodes = {
- 100: "Continue",
- 101: "Switching Protocols",
- 200: "OK",
- 201: "Created",
- 202: "Accepted",
- 203: "Non-Authoritative Information",
- 204: "No Content",
- 205: "Reset Content",
- 206: "Partial Content",
- 300: "Multiple Choice",
- 301: "Moved Permanently",
- 302: "Found",
- 303: "See Other",
- 304: "Not Modified",
- 305: "Use Proxy",
- 307: "Temporary Redirect",
- 400: "Bad Request",
- 401: "Unauthorized",
- 402: "Payment Required",
- 403: "Forbidden",
- 404: "Not Found",
- 405: "Method Not Allowed",
- 406: "Not Acceptable",
- 407: "Proxy Authentication Required",
- 408: "Request Timeout",
- 409: "Conflict",
- 410: "Gone",
- 411: "Length Required",
- 412: "Precondition Failed",
- 413: "Request Entity Too Large",
- 414: "Request-URI Too Long",
- 415: "Unsupported Media Type",
- 416: "Requested Range Not Satisfiable",
- 417: "Expectation Failed",
- 422: "Unprocessable Entity",
- 500: "Internal Server Error",
- 501: "Not Implemented",
- 502: "Bad Gateway",
- 503: "Service Unavailable",
- 504: "Gateway Timeout",
- 505: "HTTP Version Not Supported"
- };
-
- sinon.useFakeXMLHttpRequest = function () {
- sinon.FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
- if (xhr.supportsXHR) {
- global.XMLHttpRequest = xhr.GlobalXMLHttpRequest;
- }
-
- if (xhr.supportsActiveX) {
- global.ActiveXObject = xhr.GlobalActiveXObject;
- }
-
- delete sinon.FakeXMLHttpRequest.restore;
-
- if (keepOnCreate !== true) {
- delete sinon.FakeXMLHttpRequest.onCreate;
- }
- };
- if (xhr.supportsXHR) {
- global.XMLHttpRequest = sinon.FakeXMLHttpRequest;
- }
-
- if (xhr.supportsActiveX) {
- global.ActiveXObject = function ActiveXObject(objId) {
- if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
-
- return new sinon.FakeXMLHttpRequest();
- }
-
- return new xhr.GlobalActiveXObject(objId);
- };
- }
-
- return sinon.FakeXMLHttpRequest;
- };
-
- sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
-
-})((function(){ return typeof global === "object" ? global : this; })());
-
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = sinon;
-}
-
-/**
- * @depend fake_xml_http_request.js
- */
-/*jslint eqeqeq: false, onevar: false, regexp: false, plusplus: false*/
-/*global module, require, window*/
-/**
- * The Sinon "server" mimics a web server that receives requests from
- * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
- * both synchronously and asynchronously. To respond synchronuously, canned
- * answers have to be provided upfront.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-if (typeof sinon == "undefined") {
- var sinon = {};
-}
-
-sinon.fakeServer = (function () {
- var push = [].push;
- function F() {}
-
- function create(proto) {
- F.prototype = proto;
- return new F();
- }
-
- function responseArray(handler) {
- var response = handler;
-
- if (Object.prototype.toString.call(handler) != "[object Array]") {
- response = [200, {}, handler];
- }
-
- if (typeof response[2] != "string") {
- throw new TypeError("Fake server response body should be string, but was " +
- typeof response[2]);
- }
-
- return response;
- }
-
- var wloc = typeof window !== "undefined" ? window.location : {};
- var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
-
- function matchOne(response, reqMethod, reqUrl) {
- var rmeth = response.method;
- var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
- var url = response.url;
- var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
-
- return matchMethod && matchUrl;
- }
-
- function match(response, request) {
- var requestUrl = request.url;
-
- if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
- requestUrl = requestUrl.replace(rCurrLoc, "");
- }
-
- if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
- if (typeof response.response == "function") {
- var ru = response.url;
- var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
- return response.response.apply(response, args);
- }
-
- return true;
- }
-
- return false;
- }
-
- return {
- create: function () {
- var server = create(this);
- this.xhr = sinon.useFakeXMLHttpRequest();
- server.requests = [];
-
- this.xhr.onCreate = function (xhrObj) {
- server.addRequest(xhrObj);
- };
-
- return server;
- },
-
- addRequest: function addRequest(xhrObj) {
- var server = this;
- push.call(this.requests, xhrObj);
-
- xhrObj.onSend = function () {
- server.handleRequest(this);
-
- if (server.autoRespond && !server.responding) {
- setTimeout(function () {
- server.responding = false;
- server.respond();
- }, server.autoRespondAfter || 10);
-
- server.responding = true;
- }
- };
- },
-
- getHTTPMethod: function getHTTPMethod(request) {
- if (this.fakeHTTPMethods && /post/i.test(request.method)) {
- var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
- return !!matches ? matches[1] : request.method;
- }
-
- return request.method;
- },
-
- handleRequest: function handleRequest(xhr) {
- if (xhr.async) {
- if (!this.queue) {
- this.queue = [];
- }
-
- push.call(this.queue, xhr);
- } else {
- this.processRequest(xhr);
- }
- },
-
- log: function(response, request) {
- var str;
-
- str = "Request:\n" + sinon.format(request) + "\n\n";
- str += "Response:\n" + sinon.format(response) + "\n\n";
-
- sinon.log(str);
- },
-
- respondWith: function respondWith(method, url, body) {
- if (arguments.length == 1 && typeof method != "function") {
- this.response = responseArray(method);
- return;
- }
-
- if (!this.responses) { this.responses = []; }
-
- if (arguments.length == 1) {
- body = method;
- url = method = null;
- }
-
- if (arguments.length == 2) {
- body = url;
- url = method;
- method = null;
- }
-
- push.call(this.responses, {
- method: method,
- url: url,
- response: typeof body == "function" ? body : responseArray(body)
- });
- },
-
- respond: function respond() {
- if (arguments.length > 0) this.respondWith.apply(this, arguments);
- var queue = this.queue || [];
- var requests = queue.splice(0, queue.length);
- var request;
-
- while(request = requests.shift()) {
- this.processRequest(request);
- }
- },
-
- processRequest: function processRequest(request) {
- try {
- if (request.aborted) {
- return;
- }
-
- var response = this.response || [404, {}, ""];
-
- if (this.responses) {
- for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
- if (match.call(this, this.responses[i], request)) {
- response = this.responses[i].response;
- break;
- }
- }
- }
-
- if (request.readyState != 4) {
- sinon.fakeServer.log(response, request);
-
- request.respond(response[0], response[1], response[2]);
- }
- } catch (e) {
- sinon.logError("Fake server request processing", e);
- }
- },
-
- restore: function restore() {
- return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
- }
- };
-}());
-
-if (typeof module !== 'undefined' && module.exports) {
- module.exports = sinon;
-}
-
-/**
- * @depend fake_server.js
- * @depend fake_timers.js
- */
-/*jslint browser: true, eqeqeq: false, onevar: false*/
-/*global sinon*/
-/**
- * Add-on for sinon.fakeServer that automatically handles a fake timer along with
- * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
- * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
- * it polls the object for completion with setInterval. Dispite the direct
- * motivation, there is nothing jQuery-specific in this file, so it can be used
- * in any environment where the ajax implementation depends on setInterval or
- * setTimeout.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function () {
- function Server() {}
- Server.prototype = sinon.fakeServer;
-
- sinon.fakeServerWithClock = new Server();
-
- sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
- if (xhr.async) {
- if (typeof setTimeout.clock == "object") {
- this.clock = setTimeout.clock;
- } else {
- this.clock = sinon.useFakeTimers();
- this.resetClock = true;
- }
-
- if (!this.longestTimeout) {
- var clockSetTimeout = this.clock.setTimeout;
- var clockSetInterval = this.clock.setInterval;
- var server = this;
-
- this.clock.setTimeout = function (fn, timeout) {
- server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
-
- return clockSetTimeout.apply(this, arguments);
- };
-
- this.clock.setInterval = function (fn, timeout) {
- server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
-
- return clockSetInterval.apply(this, arguments);
- };
- }
- }
-
- return sinon.fakeServer.addRequest.call(this, xhr);
- };
-
- sinon.fakeServerWithClock.respond = function respond() {
- var returnVal = sinon.fakeServer.respond.apply(this, arguments);
-
- if (this.clock) {
- this.clock.tick(this.longestTimeout || 0);
- this.longestTimeout = 0;
-
- if (this.resetClock) {
- this.clock.restore();
- this.resetClock = false;
- }
- }
-
- return returnVal;
- };
-
- sinon.fakeServerWithClock.restore = function restore() {
- if (this.clock) {
- this.clock.restore();
- }
-
- return sinon.fakeServer.restore.apply(this, arguments);
- };
-}());
-
-/**
- * @depend ../sinon.js
- * @depend collection.js
- * @depend util/fake_timers.js
- * @depend util/fake_server_with_clock.js
- */
-/*jslint eqeqeq: false, onevar: false, plusplus: false*/
-/*global require, module*/
-/**
- * Manages fake collections as well as fake utilities such as Sinon's
- * timers and fake XHR implementation in one convenient object.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-if (typeof module !== "undefined" && module.exports && typeof require == "function") {
- var sinon = require("../sinon");
- sinon.extend(sinon, require("./util/fake_timers"));
-}
-
-(function () {
- var push = [].push;
-
- function exposeValue(sandbox, config, key, value) {
- if (!value) {
- return;
- }
-
- if (config.injectInto && !(key in config.injectInto)) {
- config.injectInto[key] = value;
- sandbox.injectedKeys.push(key);
- } else {
- push.call(sandbox.args, value);
- }
- }
-
- function prepareSandboxFromConfig(config) {
- var sandbox = sinon.create(sinon.sandbox);
-
- if (config.useFakeServer) {
- if (typeof config.useFakeServer == "object") {
- sandbox.serverPrototype = config.useFakeServer;
- }
-
- sandbox.useFakeServer();
- }
-
- if (config.useFakeTimers) {
- if (typeof config.useFakeTimers == "object") {
- sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
- } else {
- sandbox.useFakeTimers();
- }
- }
-
- return sandbox;
- }
-
- sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
- useFakeTimers: function useFakeTimers() {
- this.clock = sinon.useFakeTimers.apply(sinon, arguments);
-
- return this.add(this.clock);
- },
-
- serverPrototype: sinon.fakeServer,
-
- useFakeServer: function useFakeServer() {
- var proto = this.serverPrototype || sinon.fakeServer;
-
- if (!proto || !proto.create) {
- return null;
- }
-
- this.server = proto.create();
- return this.add(this.server);
- },
-
- inject: function (obj) {
- sinon.collection.inject.call(this, obj);
-
- if (this.clock) {
- obj.clock = this.clock;
- }
-
- if (this.server) {
- obj.server = this.server;
- obj.requests = this.server.requests;
- }
-
- return obj;
- },
-
- restore: function () {
- sinon.collection.restore.apply(this, arguments);
- this.restoreContext();
- },
-
- restoreContext: function () {
- if (this.injectedKeys) {
- for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
- delete this.injectInto[this.injectedKeys[i]];
- }
- this.injectedKeys = [];
- }
- },
-
- create: function (config) {
- if (!config) {
- return sinon.create(sinon.sandbox);
- }
-
- var sandbox = prepareSandboxFromConfig(config);
- sandbox.args = sandbox.args || [];
- sandbox.injectedKeys = [];
- sandbox.injectInto = config.injectInto;
- var prop, value, exposed = sandbox.inject({});
-
- if (config.properties) {
- for (var i = 0, l = config.properties.length; i < l; i++) {
- prop = config.properties[i];
- value = exposed[prop] || prop == "sandbox" && sandbox;
- exposeValue(sandbox, config, prop, value);
- }
- } else {
- exposeValue(sandbox, config, "sandbox", value);
- }
-
- return sandbox;
- }
- });
-
- sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = sinon.sandbox; });
- } else if (typeof module !== 'undefined' && module.exports) {
- module.exports = sinon.sandbox;
- }
-}());
-
-/**
- * @depend ../sinon.js
- * @depend stub.js
- * @depend mock.js
- * @depend sandbox.js
- */
-/*jslint eqeqeq: false, onevar: false, forin: true, plusplus: false*/
-/*global module, require, sinon*/
-/**
- * Test function, sandboxes fakes
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
- var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
-
- if (!sinon && commonJSModule) {
- sinon = require("../sinon");
- }
-
- if (!sinon) {
- return;
- }
-
- function test(callback) {
- var type = typeof callback;
-
- if (type != "function") {
- throw new TypeError("sinon.test needs to wrap a test function, got " + type);
- }
-
- function sinonSandboxedTest() {
- var config = sinon.getConfig(sinon.config);
- config.injectInto = config.injectIntoThis && this || config.injectInto;
- var sandbox = sinon.sandbox.create(config);
- var exception, result;
- var args = Array.prototype.slice.call(arguments).concat(sandbox.args);
-
- try {
- result = callback.apply(this, args);
- } catch (e) {
- exception = e;
- }
-
- if (typeof exception !== "undefined") {
- sandbox.restore();
- throw exception;
- }
- else {
- sandbox.verifyAndRestore();
- }
-
- return result;
- };
-
- if (callback.length) {
- return function sinonAsyncSandboxedTest(callback) {
- return sinonSandboxedTest.apply(this, arguments);
- };
- }
-
- return sinonSandboxedTest;
- }
-
- test.config = {
- injectIntoThis: true,
- injectInto: null,
- properties: ["spy", "stub", "mock", "clock", "server", "requests"],
- useFakeTimers: true,
- useFakeServer: true
- };
-
- sinon.test = test;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = test; });
- } else if (commonJSModule) {
- module.exports = test;
- }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- * @depend test.js
- */
-/*jslint eqeqeq: false, onevar: false, eqeqeq: false*/
-/*global module, require, sinon*/
-/**
- * Test case, sandboxes all test functions
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon) {
- var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
-
- if (!sinon && commonJSModule) {
- sinon = require("../sinon");
- }
-
- if (!sinon || !Object.prototype.hasOwnProperty) {
- return;
- }
-
- function createTest(property, setUp, tearDown) {
- return function () {
- if (setUp) {
- setUp.apply(this, arguments);
- }
-
- var exception, result;
-
- try {
- result = property.apply(this, arguments);
- } catch (e) {
- exception = e;
- }
-
- if (tearDown) {
- tearDown.apply(this, arguments);
- }
-
- if (exception) {
- throw exception;
- }
-
- return result;
- };
- }
-
- function testCase(tests, prefix) {
- /*jsl:ignore*/
- if (!tests || typeof tests != "object") {
- throw new TypeError("sinon.testCase needs an object with test functions");
- }
- /*jsl:end*/
-
- prefix = prefix || "test";
- var rPrefix = new RegExp("^" + prefix);
- var methods = {}, testName, property, method;
- var setUp = tests.setUp;
- var tearDown = tests.tearDown;
-
- for (testName in tests) {
- if (tests.hasOwnProperty(testName)) {
- property = tests[testName];
-
- if (/^(setUp|tearDown)$/.test(testName)) {
- continue;
- }
-
- if (typeof property == "function" && rPrefix.test(testName)) {
- method = property;
-
- if (setUp || tearDown) {
- method = createTest(property, setUp, tearDown);
- }
-
- methods[testName] = sinon.test(method);
- } else {
- methods[testName] = tests[testName];
- }
- }
- }
-
- return methods;
- }
-
- sinon.testCase = testCase;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = testCase; });
- } else if (commonJSModule) {
- module.exports = testCase;
- }
-}(typeof sinon == "object" && sinon || null));
-
-/**
- * @depend ../sinon.js
- * @depend stub.js
- */
-/*jslint eqeqeq: false, onevar: false, nomen: false, plusplus: false*/
-/*global module, require, sinon*/
-/**
- * Assertions matching the test spy retrieval interface.
- *
- * @author Christian Johansen (christian@cjohansen.no)
- * @license BSD
- *
- * Copyright (c) 2010-2013 Christian Johansen
- */
-
-(function (sinon, global) {
- var commonJSModule = typeof module !== "undefined" && module.exports && typeof require == "function";
- var slice = Array.prototype.slice;
- var assert;
-
- if (!sinon && commonJSModule) {
- sinon = require("../sinon");
- }
-
- if (!sinon) {
- return;
- }
-
- function verifyIsStub() {
- var method;
-
- for (var i = 0, l = arguments.length; i < l; ++i) {
- method = arguments[i];
-
- if (!method) {
- assert.fail("fake is not a spy");
- }
-
- if (typeof method != "function") {
- assert.fail(method + " is not a function");
- }
-
- if (typeof method.getCall != "function") {
- assert.fail(method + " is not stubbed");
- }
- }
- }
-
- function failAssertion(object, msg) {
- object = object || global;
- var failMethod = object.fail || assert.fail;
- failMethod.call(object, msg);
- }
-
- function mirrorPropAsAssertion(name, method, message) {
- if (arguments.length == 2) {
- message = method;
- method = name;
- }
-
- assert[name] = function (fake) {
- verifyIsStub(fake);
-
- var args = slice.call(arguments, 1);
- var failed = false;
-
- if (typeof method == "function") {
- failed = !method(fake);
- } else {
- failed = typeof fake[method] == "function" ?
- !fake[method].apply(fake, args) : !fake[method];
- }
-
- if (failed) {
- failAssertion(this, fake.printf.apply(fake, [message].concat(args)));
- } else {
- assert.pass(name);
- }
- };
- }
-
- function exposedName(prefix, prop) {
- return !prefix || /^fail/.test(prop) ? prop :
- prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
- }
-
- assert = {
- failException: "AssertError",
-
- fail: function fail(message) {
- var error = new Error(message);
- error.name = this.failException || assert.failException;
-
- throw error;
- },
-
- pass: function pass(assertion) {},
-
- callOrder: function assertCallOrder() {
- verifyIsStub.apply(null, arguments);
- var expected = "", actual = "";
-
- if (!sinon.calledInOrder(arguments)) {
- try {
- expected = [].join.call(arguments, ", ");
- var calls = slice.call(arguments);
- var i = calls.length;
- while (i) {
- if (!calls[--i].called) {
- calls.splice(i, 1);
- }
- }
- actual = sinon.orderByFirstCall(calls).join(", ");
- } catch (e) {
- // If this fails, we'll just fall back to the blank string
- }
-
- failAssertion(this, "expected " + expected + " to be " +
- "called in order but were called as " + actual);
- } else {
- assert.pass("callOrder");
- }
- },
-
- callCount: function assertCallCount(method, count) {
- verifyIsStub(method);
-
- if (method.callCount != count) {
- var msg = "expected %n to be called " + sinon.timesInWords(count) +
- " but was called %c%C";
- failAssertion(this, method.printf(msg));
- } else {
- assert.pass("callCount");
- }
- },
-
- expose: function expose(target, options) {
- if (!target) {
- throw new TypeError("target is null or undefined");
- }
-
- var o = options || {};
- var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
- var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
-
- for (var method in this) {
- if (method != "export" && (includeFail || !/^(fail)/.test(method))) {
- target[exposedName(prefix, method)] = this[method];
- }
- }
-
- return target;
- },
-
- match: function match(actual, expectation) {
- var matcher = sinon.match(expectation);
- if (matcher.test(actual)) {
- assert.pass("match");
- } else {
- var formatted = [
- "expected value to match",
- " expected = " + sinon.format(expectation),
- " actual = " + sinon.format(actual)
- ]
- failAssertion(this, formatted.join("\n"));
- }
- }
- };
-
- mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
- mirrorPropAsAssertion("notCalled", function (spy) { return !spy.called; },
- "expected %n to not have been called but was called %c%C");
- mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
- mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
- mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
- mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
- mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
- mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
- mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
- mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
- mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
- mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
- mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
- mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
- mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
- mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
- mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
- mirrorPropAsAssertion("threw", "%n did not throw exception%C");
- mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
-
- sinon.assert = assert;
-
- if (typeof define === "function" && define.amd) {
- define(["module"], function(module) { module.exports = assert; });
- } else if (commonJSModule) {
- module.exports = assert;
- }
-}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
-
-/**
- * @depend ../../sinon.js
- * @depend event.js
- */
-/*jslint eqeqeq: false, onevar: false*/
-/*global sinon, module, require, XDomainRequest*/
-/**
- * Fake XDomainRequest object
- */
-
-if (typeof sinon == "undefined") {
- this.sinon = {};
-}
-sinon.xdr = { XDomainRequest: this.XDomainRequest };
-
-// wrapper for global
-(function (global) {
- var xdr = sinon.xdr;
- xdr.GlobalXDomainRequest = global.XDomainRequest;
- xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
- xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false;
-
- function FakeXDomainRequest() {
- this.readyState = FakeXDomainRequest.UNSENT;
- this.requestBody = null;
- this.requestHeaders = {};
- this.status = 0;
- this.timeout = null;
-
- if (typeof FakeXDomainRequest.onCreate == "function") {
- FakeXDomainRequest.onCreate(this);
- }
- }
-
- function verifyState(xdr) {
- if (xdr.readyState !== FakeXDomainRequest.OPENED) {
- throw new Error("INVALID_STATE_ERR");
- }
-
- if (xdr.sendFlag) {
- throw new Error("INVALID_STATE_ERR");
- }
- }
-
- function verifyRequestSent(xdr) {
- if (xdr.readyState == FakeXDomainRequest.UNSENT) {
- throw new Error("Request not sent");
- }
- if (xdr.readyState == FakeXDomainRequest.DONE) {
- throw new Error("Request done");
- }
- }
-
- function verifyResponseBodyType(body) {
- if (typeof body != "string") {
- var error = new Error("Attempted to respond to fake XDomainRequest with " +
- body + ", which is not a string.");
- error.name = "InvalidBodyException";
- throw error;
- }
- }
-
- sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
- open: function open(method, url) {
- this.method = method;
- this.url = url;
-
- this.responseText = null;
- this.sendFlag = false;
-
- this.readyStateChange(FakeXDomainRequest.OPENED);
- },
-
- readyStateChange: function readyStateChange(state) {
- this.readyState = state;
- var eventName = '';
- switch (this.readyState) {
- case FakeXDomainRequest.UNSENT:
- break;
- case FakeXDomainRequest.OPENED:
- break;
- case FakeXDomainRequest.LOADING:
- if (this.sendFlag){
- //raise the progress event
- eventName = 'onprogress';
- }
- break;
- case FakeXDomainRequest.DONE:
- if (this.isTimeout){
- eventName = 'ontimeout'
- }
- else if (this.errorFlag || (this.status < 200 || this.status > 299)) {
- eventName = 'onerror';
- }
- else {
- eventName = 'onload'
- }
- break;
- }
-
- // raising event (if defined)
- if (eventName) {
- if (typeof this[eventName] == "function") {
- try {
- this[eventName]();
- } catch (e) {
- sinon.logError("Fake XHR " + eventName + " handler", e);
- }
- }
- }
- },
-
- send: function send(data) {
- verifyState(this);
-
- if (!/^(get|head)$/i.test(this.method)) {
- this.requestBody = data;
- }
- this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
-
- this.errorFlag = false;
- this.sendFlag = true;
- this.readyStateChange(FakeXDomainRequest.OPENED);
-
- if (typeof this.onSend == "function") {
- this.onSend(this);
- }
- },
-
- abort: function abort() {
- this.aborted = true;
- this.responseText = null;
- this.errorFlag = true;
-
- if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
- this.readyStateChange(sinon.FakeXDomainRequest.DONE);
- this.sendFlag = false;
- }
- },
-
- setResponseBody: function setResponseBody(body) {
- verifyRequestSent(this);
- verifyResponseBodyType(body);
-
- var chunkSize = this.chunkSize || 10;
- var index = 0;
- this.responseText = "";
-
- do {
- this.readyStateChange(FakeXDomainRequest.LOADING);
- this.responseText += body.substring(index, index + chunkSize);
- index += chunkSize;
- } while (index < body.length);
-
- this.readyStateChange(FakeXDomainRequest.DONE);
- },
-
- respond: function respond(status, contentType, body) {
- // content-type ignored, since XDomainRequest does not carry this
- // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
- // test integration across browsers
- this.status = typeof status == "number" ? status : 200;
- this.setResponseBody(body || "");
- },
-
- simulatetimeout: function(){
- this.status = 0;
- this.isTimeout = true;
- // Access to this should actually throw an error
- this.responseText = undefined;
- this.readyStateChange(FakeXDomainRequest.DONE);
- }
- });
-
- sinon.extend(FakeXDomainRequest, {
- UNSENT: 0,
- OPENED: 1,
- LOADING: 3,
- DONE: 4
- });
-
- sinon.useFakeXDomainRequest = function () {
- sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
- if (xdr.supportsXDR) {
- global.XDomainRequest = xdr.GlobalXDomainRequest;
- }
-
- delete sinon.FakeXDomainRequest.restore;
-
- if (keepOnCreate !== true) {
- delete sinon.FakeXDomainRequest.onCreate;
- }
- };
- if (xdr.supportsXDR) {
- global.XDomainRequest = sinon.FakeXDomainRequest;
- }
- return sinon.FakeXDomainRequest;
- };
-
- sinon.FakeXDomainRequest = FakeXDomainRequest;
-})(this);
-
-if (typeof module == "object" && typeof require == "function") {
- module.exports = sinon;
-}
-
-return sinon;}.call(typeof window != 'undefined' && window || {}));
diff --git a/resources/lib/sinonjs/sinon-1.15.4.js b/resources/lib/sinonjs/sinon-1.15.4.js
new file mode 100644
index 00000000..20bc9e20
--- /dev/null
+++ b/resources/lib/sinonjs/sinon-1.15.4.js
@@ -0,0 +1,5949 @@
+/**
+ * Sinon.JS 1.15.4, 2015/06/27
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
+ *
+ * (The BSD License)
+ *
+ * Copyright (c) 2010-2014, Christian Johansen, christian@cjohansen.no
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * * Neither the name of Christian Johansen nor the names of his contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+(function (root, factory) {
+ 'use strict';
+ if (typeof define === 'function' && define.amd) {
+ define('sinon', [], function () {
+ return (root.sinon = factory());
+ });
+ } else if (typeof exports === 'object') {
+ module.exports = factory();
+ } else {
+ root.sinon = factory();
+ }
+}(this, function () {
+ 'use strict';
+ var samsam, formatio, lolex;
+ (function () {
+ function define(mod, deps, fn) {
+ if (mod == "samsam") {
+ samsam = deps();
+ } else if (typeof deps === "function" && mod.length === 0) {
+ lolex = deps();
+ } else if (typeof fn === "function") {
+ formatio = fn(samsam);
+ }
+ }
+ define.amd = {};
+((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) ||
+ (typeof module === "object" &&
+ function (m) { module.exports = m(); }) || // Node
+ function (m) { this.samsam = m(); } // Browser globals
+)(function () {
+ var o = Object.prototype;
+ var div = typeof document !== "undefined" && document.createElement("div");
+
+ function isNaN(value) {
+ // Unlike global isNaN, this avoids type coercion
+ // typeof check avoids IE host object issues, hat tip to
+ // lodash
+ var val = value; // JsLint thinks value !== value is "weird"
+ return typeof value === "number" && value !== val;
+ }
+
+ function getClass(value) {
+ // Returns the internal [[Class]] by calling Object.prototype.toString
+ // with the provided value as this. Return value is a string, naming the
+ // internal class, e.g. "Array"
+ return o.toString.call(value).split(/[ \]]/)[1];
+ }
+
+ /**
+ * @name samsam.isArguments
+ * @param Object object
+ *
+ * Returns ``true`` if ``object`` is an ``arguments`` object,
+ * ``false`` otherwise.
+ */
+ function isArguments(object) {
+ if (getClass(object) === 'Arguments') { return true; }
+ if (typeof object !== "object" || typeof object.length !== "number" ||
+ getClass(object) === "Array") {
+ return false;
+ }
+ if (typeof object.callee == "function") { return true; }
+ try {
+ object[object.length] = 6;
+ delete object[object.length];
+ } catch (e) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @name samsam.isElement
+ * @param Object object
+ *
+ * Returns ``true`` if ``object`` is a DOM element node. Unlike
+ * Underscore.js/lodash, this function will return ``false`` if ``object``
+ * is an *element-like* object, i.e. a regular object with a ``nodeType``
+ * property that holds the value ``1``.
+ */
+ function isElement(object) {
+ if (!object || object.nodeType !== 1 || !div) { return false; }
+ try {
+ object.appendChild(div);
+ object.removeChild(div);
+ } catch (e) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * @name samsam.keys
+ * @param Object object
+ *
+ * Return an array of own property names.
+ */
+ function keys(object) {
+ var ks = [], prop;
+ for (prop in object) {
+ if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); }
+ }
+ return ks;
+ }
+
+ /**
+ * @name samsam.isDate
+ * @param Object value
+ *
+ * Returns true if the object is a ``Date``, or *date-like*. Duck typing
+ * of date objects work by checking that the object has a ``getTime``
+ * function whose return value equals the return value from the object's
+ * ``valueOf``.
+ */
+ function isDate(value) {
+ return typeof value.getTime == "function" &&
+ value.getTime() == value.valueOf();
+ }
+
+ /**
+ * @name samsam.isNegZero
+ * @param Object value
+ *
+ * Returns ``true`` if ``value`` is ``-0``.
+ */
+ function isNegZero(value) {
+ return value === 0 && 1 / value === -Infinity;
+ }
+
+ /**
+ * @name samsam.equal
+ * @param Object obj1
+ * @param Object obj2
+ *
+ * Returns ``true`` if two objects are strictly equal. Compared to
+ * ``===`` there are two exceptions:
+ *
+ * - NaN is considered equal to NaN
+ * - -0 and +0 are not considered equal
+ */
+ function identical(obj1, obj2) {
+ if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) {
+ return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2);
+ }
+ }
+
+
+ /**
+ * @name samsam.deepEqual
+ * @param Object obj1
+ * @param Object obj2
+ *
+ * Deep equal comparison. Two values are "deep equal" if:
+ *
+ * - They are equal, according to samsam.identical
+ * - They are both date objects representing the same time
+ * - They are both arrays containing elements that are all deepEqual
+ * - They are objects with the same set of properties, and each property
+ * in ``obj1`` is deepEqual to the corresponding property in ``obj2``
+ *
+ * Supports cyclic objects.
+ */
+ function deepEqualCyclic(obj1, obj2) {
+
+ // used for cyclic comparison
+ // contain already visited objects
+ var objects1 = [],
+ objects2 = [],
+ // contain pathes (position in the object structure)
+ // of the already visited objects
+ // indexes same as in objects arrays
+ paths1 = [],
+ paths2 = [],
+ // contains combinations of already compared objects
+ // in the manner: { "$1['ref']$2['ref']": true }
+ compared = {};
+
+ /**
+ * used to check, if the value of a property is an object
+ * (cyclic logic is only needed for objects)
+ * only needed for cyclic logic
+ */
+ function isObject(value) {
+
+ if (typeof value === 'object' && value !== null &&
+ !(value instanceof Boolean) &&
+ !(value instanceof Date) &&
+ !(value instanceof Number) &&
+ !(value instanceof RegExp) &&
+ !(value instanceof String)) {
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * returns the index of the given object in the
+ * given objects array, -1 if not contained
+ * only needed for cyclic logic
+ */
+ function getIndex(objects, obj) {
+
+ var i;
+ for (i = 0; i < objects.length; i++) {
+ if (objects[i] === obj) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ // does the recursion for the deep equal check
+ return (function deepEqual(obj1, obj2, path1, path2) {
+ var type1 = typeof obj1;
+ var type2 = typeof obj2;
+
+ // == null also matches undefined
+ if (obj1 === obj2 ||
+ isNaN(obj1) || isNaN(obj2) ||
+ obj1 == null || obj2 == null ||
+ type1 !== "object" || type2 !== "object") {
+
+ return identical(obj1, obj2);
+ }
+
+ // Elements are only equal if identical(expected, actual)
+ if (isElement(obj1) || isElement(obj2)) { return false; }
+
+ var isDate1 = isDate(obj1), isDate2 = isDate(obj2);
+ if (isDate1 || isDate2) {
+ if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) {
+ return false;
+ }
+ }
+
+ if (obj1 instanceof RegExp && obj2 instanceof RegExp) {
+ if (obj1.toString() !== obj2.toString()) { return false; }
+ }
+
+ var class1 = getClass(obj1);
+ var class2 = getClass(obj2);
+ var keys1 = keys(obj1);
+ var keys2 = keys(obj2);
+
+ if (isArguments(obj1) || isArguments(obj2)) {
+ if (obj1.length !== obj2.length) { return false; }
+ } else {
+ if (type1 !== type2 || class1 !== class2 ||
+ keys1.length !== keys2.length) {
+ return false;
+ }
+ }
+
+ var key, i, l,
+ // following vars are used for the cyclic logic
+ value1, value2,
+ isObject1, isObject2,
+ index1, index2,
+ newPath1, newPath2;
+
+ for (i = 0, l = keys1.length; i < l; i++) {
+ key = keys1[i];
+ if (!o.hasOwnProperty.call(obj2, key)) {
+ return false;
+ }
+
+ // Start of the cyclic logic
+
+ value1 = obj1[key];
+ value2 = obj2[key];
+
+ isObject1 = isObject(value1);
+ isObject2 = isObject(value2);
+
+ // determine, if the objects were already visited
+ // (it's faster to check for isObject first, than to
+ // get -1 from getIndex for non objects)
+ index1 = isObject1 ? getIndex(objects1, value1) : -1;
+ index2 = isObject2 ? getIndex(objects2, value2) : -1;
+
+ // determine the new pathes of the objects
+ // - for non cyclic objects the current path will be extended
+ // by current property name
+ // - for cyclic objects the stored path is taken
+ newPath1 = index1 !== -1
+ ? paths1[index1]
+ : path1 + '[' + JSON.stringify(key) + ']';
+ newPath2 = index2 !== -1
+ ? paths2[index2]
+ : path2 + '[' + JSON.stringify(key) + ']';
+
+ // stop recursion if current objects are already compared
+ if (compared[newPath1 + newPath2]) {
+ return true;
+ }
+
+ // remember the current objects and their pathes
+ if (index1 === -1 && isObject1) {
+ objects1.push(value1);
+ paths1.push(newPath1);
+ }
+ if (index2 === -1 && isObject2) {
+ objects2.push(value2);
+ paths2.push(newPath2);
+ }
+
+ // remember that the current objects are already compared
+ if (isObject1 && isObject2) {
+ compared[newPath1 + newPath2] = true;
+ }
+
+ // End of cyclic logic
+
+ // neither value1 nor value2 is a cycle
+ // continue with next level
+ if (!deepEqual(value1, value2, newPath1, newPath2)) {
+ return false;
+ }
+ }
+
+ return true;
+
+ }(obj1, obj2, '$1', '$2'));
+ }
+
+ var match;
+
+ function arrayContains(array, subset) {
+ if (subset.length === 0) { return true; }
+ var i, l, j, k;
+ for (i = 0, l = array.length; i < l; ++i) {
+ if (match(array[i], subset[0])) {
+ for (j = 0, k = subset.length; j < k; ++j) {
+ if (!match(array[i + j], subset[j])) { return false; }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @name samsam.match
+ * @param Object object
+ * @param Object matcher
+ *
+ * Compare arbitrary value ``object`` with matcher.
+ */
+ match = function match(object, matcher) {
+ if (matcher && typeof matcher.test === "function") {
+ return matcher.test(object);
+ }
+
+ if (typeof matcher === "function") {
+ return matcher(object) === true;
+ }
+
+ if (typeof matcher === "string") {
+ matcher = matcher.toLowerCase();
+ var notNull = typeof object === "string" || !!object;
+ return notNull &&
+ (String(object)).toLowerCase().indexOf(matcher) >= 0;
+ }
+
+ if (typeof matcher === "number") {
+ return matcher === object;
+ }
+
+ if (typeof matcher === "boolean") {
+ return matcher === object;
+ }
+
+ if (typeof(matcher) === "undefined") {
+ return typeof(object) === "undefined";
+ }
+
+ if (matcher === null) {
+ return object === null;
+ }
+
+ if (getClass(object) === "Array" && getClass(matcher) === "Array") {
+ return arrayContains(object, matcher);
+ }
+
+ if (matcher && typeof matcher === "object") {
+ if (matcher === object) {
+ return true;
+ }
+ var prop;
+ for (prop in matcher) {
+ var value = object[prop];
+ if (typeof value === "undefined" &&
+ typeof object.getAttribute === "function") {
+ value = object.getAttribute(prop);
+ }
+ if (matcher[prop] === null || typeof matcher[prop] === 'undefined') {
+ if (value !== matcher[prop]) {
+ return false;
+ }
+ } else if (typeof value === "undefined" || !match(value, matcher[prop])) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ throw new Error("Matcher was not a string, a number, a " +
+ "function, a boolean or an object");
+ };
+
+ return {
+ isArguments: isArguments,
+ isElement: isElement,
+ isDate: isDate,
+ isNegZero: isNegZero,
+ identical: identical,
+ deepEqual: deepEqualCyclic,
+ match: match,
+ keys: keys
+ };
+});
+((typeof define === "function" && define.amd && function (m) {
+ define("formatio", ["samsam"], m);
+}) || (typeof module === "object" && function (m) {
+ module.exports = m(require("samsam"));
+}) || function (m) { this.formatio = m(this.samsam); }
+)(function (samsam) {
+
+ var formatio = {
+ excludeConstructors: ["Object", /^.$/],
+ quoteStrings: true,
+ limitChildrenCount: 0
+ };
+
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ var specialObjects = [];
+ if (typeof global !== "undefined") {
+ specialObjects.push({ object: global, value: "[object global]" });
+ }
+ if (typeof document !== "undefined") {
+ specialObjects.push({
+ object: document,
+ value: "[object HTMLDocument]"
+ });
+ }
+ if (typeof window !== "undefined") {
+ specialObjects.push({ object: window, value: "[object Window]" });
+ }
+
+ function functionName(func) {
+ if (!func) { return ""; }
+ if (func.displayName) { return func.displayName; }
+ if (func.name) { return func.name; }
+ var matches = func.toString().match(/function\s+([^\(]+)/m);
+ return (matches && matches[1]) || "";
+ }
+
+ function constructorName(f, object) {
+ var name = functionName(object && object.constructor);
+ var excludes = f.excludeConstructors ||
+ formatio.excludeConstructors || [];
+
+ var i, l;
+ for (i = 0, l = excludes.length; i < l; ++i) {
+ if (typeof excludes[i] === "string" && excludes[i] === name) {
+ return "";
+ } else if (excludes[i].test && excludes[i].test(name)) {
+ return "";
+ }
+ }
+
+ return name;
+ }
+
+ function isCircular(object, objects) {
+ if (typeof object !== "object") { return false; }
+ var i, l;
+ for (i = 0, l = objects.length; i < l; ++i) {
+ if (objects[i] === object) { return true; }
+ }
+ return false;
+ }
+
+ function ascii(f, object, processed, indent) {
+ if (typeof object === "string") {
+ var qs = f.quoteStrings;
+ var quote = typeof qs !== "boolean" || qs;
+ return processed || quote ? '"' + object + '"' : object;
+ }
+
+ if (typeof object === "function" && !(object instanceof RegExp)) {
+ return ascii.func(object);
+ }
+
+ processed = processed || [];
+
+ if (isCircular(object, processed)) { return "[Circular]"; }
+
+ if (Object.prototype.toString.call(object) === "[object Array]") {
+ return ascii.array.call(f, object, processed);
+ }
+
+ if (!object) { return String((1/object) === -Infinity ? "-0" : object); }
+ if (samsam.isElement(object)) { return ascii.element(object); }
+
+ if (typeof object.toString === "function" &&
+ object.toString !== Object.prototype.toString) {
+ return object.toString();
+ }
+
+ var i, l;
+ for (i = 0, l = specialObjects.length; i < l; i++) {
+ if (object === specialObjects[i].object) {
+ return specialObjects[i].value;
+ }
+ }
+
+ return ascii.object.call(f, object, processed, indent);
+ }
+
+ ascii.func = function (func) {
+ return "function " + functionName(func) + "() {}";
+ };
+
+ ascii.array = function (array, processed) {
+ processed = processed || [];
+ processed.push(array);
+ var pieces = [];
+ var i, l;
+ l = (this.limitChildrenCount > 0) ?
+ Math.min(this.limitChildrenCount, array.length) : array.length;
+
+ for (i = 0; i < l; ++i) {
+ pieces.push(ascii(this, array[i], processed));
+ }
+
+ if(l < array.length)
+ pieces.push("[... " + (array.length - l) + " more elements]");
+
+ return "[" + pieces.join(", ") + "]";
+ };
+
+ ascii.object = function (object, processed, indent) {
+ processed = processed || [];
+ processed.push(object);
+ indent = indent || 0;
+ var pieces = [], properties = samsam.keys(object).sort();
+ var length = 3;
+ var prop, str, obj, i, k, l;
+ l = (this.limitChildrenCount > 0) ?
+ Math.min(this.limitChildrenCount, properties.length) : properties.length;
+
+ for (i = 0; i < l; ++i) {
+ prop = properties[i];
+ obj = object[prop];
+
+ if (isCircular(obj, processed)) {
+ str = "[Circular]";
+ } else {
+ str = ascii(this, obj, processed, indent + 2);
+ }
+
+ str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str;
+ length += str.length;
+ pieces.push(str);
+ }
+
+ var cons = constructorName(this, object);
+ var prefix = cons ? "[" + cons + "] " : "";
+ var is = "";
+ for (i = 0, k = indent; i < k; ++i) { is += " "; }
+
+ if(l < properties.length)
+ pieces.push("[... " + (properties.length - l) + " more elements]");
+
+ if (length + indent > 80) {
+ return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" +
+ is + "}";
+ }
+ return prefix + "{ " + pieces.join(", ") + " }";
+ };
+
+ ascii.element = function (element) {
+ var tagName = element.tagName.toLowerCase();
+ var attrs = element.attributes, attr, pairs = [], attrName, i, l, val;
+
+ for (i = 0, l = attrs.length; i < l; ++i) {
+ attr = attrs.item(i);
+ attrName = attr.nodeName.toLowerCase().replace("html:", "");
+ val = attr.nodeValue;
+ if (attrName !== "contenteditable" || val !== "inherit") {
+ if (!!val) { pairs.push(attrName + "=\"" + val + "\""); }
+ }
+ }
+
+ var formatted = "<" + tagName + (pairs.length > 0 ? " " : "");
+ var content = element.innerHTML;
+
+ if (content.length > 20) {
+ content = content.substr(0, 20) + "[...]";
+ }
+
+ var res = formatted + pairs.join(" ") + ">" + content +
+ "</" + tagName + ">";
+
+ return res.replace(/ contentEditable="inherit"/, "");
+ };
+
+ function Formatio(options) {
+ for (var opt in options) {
+ this[opt] = options[opt];
+ }
+ }
+
+ Formatio.prototype = {
+ functionName: functionName,
+
+ configure: function (options) {
+ return new Formatio(options);
+ },
+
+ constructorName: function (object) {
+ return constructorName(this, object);
+ },
+
+ ascii: function (object, processed, indent) {
+ return ascii(this, object, processed, indent);
+ }
+ };
+
+ return Formatio.prototype;
+});
+!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.lolex=e()}}(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
+(function (global){
+/*jslint eqeqeq: false, plusplus: false, evil: true, onevar: false, browser: true, forin: false*/
+/*global global*/
+/**
+ * @author Christian Johansen (christian@cjohansen.no) and contributors
+ * @license BSD
+ *
+ * Copyright (c) 2010-2014 Christian Johansen
+ */
+
+// node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref()
+// browsers, a number.
+// see https://github.com/cjohansen/Sinon.JS/pull/436
+var timeoutResult = setTimeout(function() {}, 0);
+var addTimerReturnsObject = typeof timeoutResult === "object";
+clearTimeout(timeoutResult);
+
+var NativeDate = Date;
+var id = 1;
+
+/**
+ * Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into
+ * number of milliseconds. This is used to support human-readable strings passed
+ * to clock.tick()
+ */
+function parseTime(str) {
+ if (!str) {
+ return 0;
+ }
+
+ var strings = str.split(":");
+ var l = strings.length, i = l;
+ var ms = 0, parsed;
+
+ if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) {
+ throw new Error("tick only understands numbers and 'h:m:s'");
+ }
+
+ while (i--) {
+ parsed = parseInt(strings[i], 10);
+
+ if (parsed >= 60) {
+ throw new Error("Invalid time " + str);
+ }
+
+ ms += parsed * Math.pow(60, (l - i - 1));
+ }
+
+ return ms * 1000;
+}
+
+/**
+ * Used to grok the `now` parameter to createClock.
+ */
+function getEpoch(epoch) {
+ if (!epoch) { return 0; }
+ if (typeof epoch.getTime === "function") { return epoch.getTime(); }
+ if (typeof epoch === "number") { return epoch; }
+ throw new TypeError("now should be milliseconds since UNIX epoch");
+}
+
+function inRange(from, to, timer) {
+ return timer && timer.callAt >= from && timer.callAt <= to;
+}
+
+function mirrorDateProperties(target, source) {
+ if (source.now) {
+ target.now = function now() {
+ return target.clock.now;
+ };
+ } else {
+ delete target.now;
+ }
+
+ if (source.toSource) {
+ target.toSource = function toSource() {
+ return source.toSource();
+ };
+ } else {
+ delete target.toSource;
+ }
+
+ target.toString = function toString() {
+ return source.toString();
+ };
+
+ target.prototype = source.prototype;
+ target.parse = source.parse;
+ target.UTC = source.UTC;
+ target.prototype.toUTCString = source.prototype.toUTCString;
+
+ for (var prop in source) {
+ if (source.hasOwnProperty(prop)) {
+ target[prop] = source[prop];
+ }
+ }
+
+ return target;
+}
+
+function createDate() {
+ function ClockDate(year, month, date, hour, minute, second, ms) {
+ // Defensive and verbose to avoid potential harm in passing
+ // explicit undefined when user does not pass argument
+ switch (arguments.length) {
+ case 0:
+ return new NativeDate(ClockDate.clock.now);
+ case 1:
+ return new NativeDate(year);
+ case 2:
+ return new NativeDate(year, month);
+ case 3:
+ return new NativeDate(year, month, date);
+ case 4:
+ return new NativeDate(year, month, date, hour);
+ case 5:
+ return new NativeDate(year, month, date, hour, minute);
+ case 6:
+ return new NativeDate(year, month, date, hour, minute, second);
+ default:
+ return new NativeDate(year, month, date, hour, minute, second, ms);
+ }
+ }
+
+ return mirrorDateProperties(ClockDate, NativeDate);
+}
+
+function addTimer(clock, timer) {
+ if (typeof timer.func === "undefined") {
+ throw new Error("Callback must be provided to timer calls");
+ }
+
+ if (!clock.timers) {
+ clock.timers = {};
+ }
+
+ timer.id = id++;
+ timer.createdAt = clock.now;
+ timer.callAt = clock.now + (timer.delay || 0);
+
+ clock.timers[timer.id] = timer;
+
+ if (addTimerReturnsObject) {
+ return {
+ id: timer.id,
+ ref: function() {},
+ unref: function() {}
+ };
+ }
+ else {
+ return timer.id;
+ }
+}
+
+function firstTimerInRange(clock, from, to) {
+ var timers = clock.timers, timer = null;
+
+ for (var id in timers) {
+ if (!inRange(from, to, timers[id])) {
+ continue;
+ }
+
+ if (!timer || ~compareTimers(timer, timers[id])) {
+ timer = timers[id];
+ }
+ }
+
+ return timer;
+}
+
+function compareTimers(a, b) {
+ // Sort first by absolute timing
+ if (a.callAt < b.callAt) {
+ return -1;
+ }
+ if (a.callAt > b.callAt) {
+ return 1;
+ }
+
+ // Sort next by immediate, immediate timers take precedence
+ if (a.immediate && !b.immediate) {
+ return -1;
+ }
+ if (!a.immediate && b.immediate) {
+ return 1;
+ }
+
+ // Sort next by creation time, earlier-created timers take precedence
+ if (a.createdAt < b.createdAt) {
+ return -1;
+ }
+ if (a.createdAt > b.createdAt) {
+ return 1;
+ }
+
+ // Sort next by id, lower-id timers take precedence
+ if (a.id < b.id) {
+ return -1;
+ }
+ if (a.id > b.id) {
+ return 1;
+ }
+
+ // As timer ids are unique, no fallback `0` is necessary
+}
+
+function callTimer(clock, timer) {
+ if (typeof timer.interval == "number") {
+ clock.timers[timer.id].callAt += timer.interval;
+ } else {
+ delete clock.timers[timer.id];
+ }
+
+ try {
+ if (typeof timer.func == "function") {
+ timer.func.apply(null, timer.args);
+ } else {
+ eval(timer.func);
+ }
+ } catch (e) {
+ var exception = e;
+ }
+
+ if (!clock.timers[timer.id]) {
+ if (exception) {
+ throw exception;
+ }
+ return;
+ }
+
+ if (exception) {
+ throw exception;
+ }
+}
+
+function uninstall(clock, target) {
+ var method;
+
+ for (var i = 0, l = clock.methods.length; i < l; i++) {
+ method = clock.methods[i];
+
+ if (target[method].hadOwnProperty) {
+ target[method] = clock["_" + method];
+ } else {
+ try {
+ delete target[method];
+ } catch (e) {}
+ }
+ }
+
+ // Prevent multiple executions which will completely remove these props
+ clock.methods = [];
+}
+
+function hijackMethod(target, method, clock) {
+ clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method);
+ clock["_" + method] = target[method];
+
+ if (method == "Date") {
+ var date = mirrorDateProperties(clock[method], target[method]);
+ target[method] = date;
+ } else {
+ target[method] = function () {
+ return clock[method].apply(clock, arguments);
+ };
+
+ for (var prop in clock[method]) {
+ if (clock[method].hasOwnProperty(prop)) {
+ target[method][prop] = clock[method][prop];
+ }
+ }
+ }
+
+ target[method].clock = clock;
+}
+
+var timers = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
+ clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate: undefined),
+ setInterval: setInterval,
+ clearInterval: clearInterval,
+ Date: Date
+};
+
+var keys = Object.keys || function (obj) {
+ var ks = [];
+ for (var key in obj) {
+ ks.push(key);
+ }
+ return ks;
+};
+
+exports.timers = timers;
+
+var createClock = exports.createClock = function (now) {
+ var clock = {
+ now: getEpoch(now),
+ timeouts: {},
+ Date: createDate()
+ };
+
+ clock.Date.clock = clock;
+
+ clock.setTimeout = function setTimeout(func, timeout) {
+ return addTimer(clock, {
+ func: func,
+ args: Array.prototype.slice.call(arguments, 2),
+ delay: timeout
+ });
+ };
+
+ clock.clearTimeout = function clearTimeout(timerId) {
+ if (!timerId) {
+ // null appears to be allowed in most browsers, and appears to be
+ // relied upon by some libraries, like Bootstrap carousel
+ return;
+ }
+ if (!clock.timers) {
+ clock.timers = [];
+ }
+ // in Node, timerId is an object with .ref()/.unref(), and
+ // its .id field is the actual timer id.
+ if (typeof timerId === "object") {
+ timerId = timerId.id
+ }
+ if (timerId in clock.timers) {
+ delete clock.timers[timerId];
+ }
+ };
+
+ clock.setInterval = function setInterval(func, timeout) {
+ return addTimer(clock, {
+ func: func,
+ args: Array.prototype.slice.call(arguments, 2),
+ delay: timeout,
+ interval: timeout
+ });
+ };
+
+ clock.clearInterval = function clearInterval(timerId) {
+ clock.clearTimeout(timerId);
+ };
+
+ clock.setImmediate = function setImmediate(func) {
+ return addTimer(clock, {
+ func: func,
+ args: Array.prototype.slice.call(arguments, 1),
+ immediate: true
+ });
+ };
+
+ clock.clearImmediate = function clearImmediate(timerId) {
+ clock.clearTimeout(timerId);
+ };
+
+ clock.tick = function tick(ms) {
+ ms = typeof ms == "number" ? ms : parseTime(ms);
+ var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now;
+ var timer = firstTimerInRange(clock, tickFrom, tickTo);
+
+ var firstException;
+ while (timer && tickFrom <= tickTo) {
+ if (clock.timers[timer.id]) {
+ tickFrom = clock.now = timer.callAt;
+ try {
+ callTimer(clock, timer);
+ } catch (e) {
+ firstException = firstException || e;
+ }
+ }
+
+ timer = firstTimerInRange(clock, previous, tickTo);
+ previous = tickFrom;
+ }
+
+ clock.now = tickTo;
+
+ if (firstException) {
+ throw firstException;
+ }
+
+ return clock.now;
+ };
+
+ clock.reset = function reset() {
+ clock.timers = {};
+ };
+
+ return clock;
+};
+
+exports.install = function install(target, now, toFake) {
+ if (typeof target === "number") {
+ toFake = now;
+ now = target;
+ target = null;
+ }
+
+ if (!target) {
+ target = global;
+ }
+
+ var clock = createClock(now);
+
+ clock.uninstall = function () {
+ uninstall(clock, target);
+ };
+
+ clock.methods = toFake || [];
+
+ if (clock.methods.length === 0) {
+ clock.methods = keys(timers);
+ }
+
+ for (var i = 0, l = clock.methods.length; i < l; i++) {
+ hijackMethod(target, clock.methods[i], clock);
+ }
+
+ return clock;
+};
+
+}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
+},{}]},{},[1])(1)
+});
+ })();
+ var define;
+/**
+ * Sinon core utilities. For internal use only.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+var sinon = (function () {
+"use strict";
+
+ var sinon;
+ var isNode = typeof module !== "undefined" && module.exports && typeof require === "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ sinon = module.exports = require("./sinon/util/core");
+ require("./sinon/extend");
+ require("./sinon/typeOf");
+ require("./sinon/times_in_words");
+ require("./sinon/spy");
+ require("./sinon/call");
+ require("./sinon/behavior");
+ require("./sinon/stub");
+ require("./sinon/mock");
+ require("./sinon/collection");
+ require("./sinon/assert");
+ require("./sinon/sandbox");
+ require("./sinon/test");
+ require("./sinon/test_case");
+ require("./sinon/match");
+ require("./sinon/format");
+ require("./sinon/log_error");
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ sinon = module.exports;
+ } else {
+ sinon = {};
+ }
+
+ return sinon;
+}());
+
+/**
+ * @depend ../../sinon.js
+ */
+/**
+ * Sinon core utilities. For internal use only.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ var div = typeof document != "undefined" && document.createElement("div");
+ var hasOwn = Object.prototype.hasOwnProperty;
+
+ function isDOMNode(obj) {
+ var success = false;
+
+ try {
+ obj.appendChild(div);
+ success = div.parentNode == obj;
+ } catch (e) {
+ return false;
+ } finally {
+ try {
+ obj.removeChild(div);
+ } catch (e) {
+ // Remove failed, not much we can do about that
+ }
+ }
+
+ return success;
+ }
+
+ function isElement(obj) {
+ return div && obj && obj.nodeType === 1 && isDOMNode(obj);
+ }
+
+ function isFunction(obj) {
+ return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply);
+ }
+
+ function isReallyNaN(val) {
+ return typeof val === "number" && isNaN(val);
+ }
+
+ function mirrorProperties(target, source) {
+ for (var prop in source) {
+ if (!hasOwn.call(target, prop)) {
+ target[prop] = source[prop];
+ }
+ }
+ }
+
+ function isRestorable(obj) {
+ return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon;
+ }
+
+ // Cheap way to detect if we have ES5 support.
+ var hasES5Support = "keys" in Object;
+
+ function makeApi(sinon) {
+ sinon.wrapMethod = function wrapMethod(object, property, method) {
+ if (!object) {
+ throw new TypeError("Should wrap property of object");
+ }
+
+ if (typeof method != "function" && typeof method != "object") {
+ throw new TypeError("Method wrapper should be a function or a property descriptor");
+ }
+
+ function checkWrappedMethod(wrappedMethod) {
+ if (!isFunction(wrappedMethod)) {
+ error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
+ property + " as function");
+ } else if (wrappedMethod.restore && wrappedMethod.restore.sinon) {
+ error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
+ } else if (wrappedMethod.calledBefore) {
+ var verb = !!wrappedMethod.returns ? "stubbed" : "spied on";
+ error = new TypeError("Attempted to wrap " + property + " which is already " + verb);
+ }
+
+ if (error) {
+ if (wrappedMethod && wrappedMethod.stackTrace) {
+ error.stack += "\n--------------\n" + wrappedMethod.stackTrace;
+ }
+ throw error;
+ }
+ }
+
+ var error, wrappedMethod;
+
+ // IE 8 does not support hasOwnProperty on the window object and Firefox has a problem
+ // when using hasOwn.call on objects from other frames.
+ var owned = object.hasOwnProperty ? object.hasOwnProperty(property) : hasOwn.call(object, property);
+
+ if (hasES5Support) {
+ var methodDesc = (typeof method == "function") ? {value: method} : method,
+ wrappedMethodDesc = sinon.getPropertyDescriptor(object, property),
+ i;
+
+ if (!wrappedMethodDesc) {
+ error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " +
+ property + " as function");
+ } else if (wrappedMethodDesc.restore && wrappedMethodDesc.restore.sinon) {
+ error = new TypeError("Attempted to wrap " + property + " which is already wrapped");
+ }
+ if (error) {
+ if (wrappedMethodDesc && wrappedMethodDesc.stackTrace) {
+ error.stack += "\n--------------\n" + wrappedMethodDesc.stackTrace;
+ }
+ throw error;
+ }
+
+ var types = sinon.objectKeys(methodDesc);
+ for (i = 0; i < types.length; i++) {
+ wrappedMethod = wrappedMethodDesc[types[i]];
+ checkWrappedMethod(wrappedMethod);
+ }
+
+ mirrorProperties(methodDesc, wrappedMethodDesc);
+ for (i = 0; i < types.length; i++) {
+ mirrorProperties(methodDesc[types[i]], wrappedMethodDesc[types[i]]);
+ }
+ Object.defineProperty(object, property, methodDesc);
+ } else {
+ wrappedMethod = object[property];
+ checkWrappedMethod(wrappedMethod);
+ object[property] = method;
+ method.displayName = property;
+ }
+
+ method.displayName = property;
+
+ // Set up a stack trace which can be used later to find what line of
+ // code the original method was created on.
+ method.stackTrace = (new Error("Stack Trace for original")).stack;
+
+ method.restore = function () {
+ // For prototype properties try to reset by delete first.
+ // If this fails (ex: localStorage on mobile safari) then force a reset
+ // via direct assignment.
+ if (!owned) {
+ // In some cases `delete` may throw an error
+ try {
+ delete object[property];
+ } catch (e) {}
+ // For native code functions `delete` fails without throwing an error
+ // on Chrome < 43, PhantomJS, etc.
+ } else if (hasES5Support) {
+ Object.defineProperty(object, property, wrappedMethodDesc);
+ }
+
+ // Use strict equality comparison to check failures then force a reset
+ // via direct assignment.
+ if (object[property] === method) {
+ object[property] = wrappedMethod;
+ }
+ };
+
+ method.restore.sinon = true;
+
+ if (!hasES5Support) {
+ mirrorProperties(method, wrappedMethod);
+ }
+
+ return method;
+ };
+
+ sinon.create = function create(proto) {
+ var F = function () {};
+ F.prototype = proto;
+ return new F();
+ };
+
+ sinon.deepEqual = function deepEqual(a, b) {
+ if (sinon.match && sinon.match.isMatcher(a)) {
+ return a.test(b);
+ }
+
+ if (typeof a != "object" || typeof b != "object") {
+ if (isReallyNaN(a) && isReallyNaN(b)) {
+ return true;
+ } else {
+ return a === b;
+ }
+ }
+
+ if (isElement(a) || isElement(b)) {
+ return a === b;
+ }
+
+ if (a === b) {
+ return true;
+ }
+
+ if ((a === null && b !== null) || (a !== null && b === null)) {
+ return false;
+ }
+
+ if (a instanceof RegExp && b instanceof RegExp) {
+ return (a.source === b.source) && (a.global === b.global) &&
+ (a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline);
+ }
+
+ var aString = Object.prototype.toString.call(a);
+ if (aString != Object.prototype.toString.call(b)) {
+ return false;
+ }
+
+ if (aString == "[object Date]") {
+ return a.valueOf() === b.valueOf();
+ }
+
+ var prop, aLength = 0, bLength = 0;
+
+ if (aString == "[object Array]" && a.length !== b.length) {
+ return false;
+ }
+
+ for (prop in a) {
+ aLength += 1;
+
+ if (!(prop in b)) {
+ return false;
+ }
+
+ if (!deepEqual(a[prop], b[prop])) {
+ return false;
+ }
+ }
+
+ for (prop in b) {
+ bLength += 1;
+ }
+
+ return aLength == bLength;
+ };
+
+ sinon.functionName = function functionName(func) {
+ var name = func.displayName || func.name;
+
+ // Use function decomposition as a last resort to get function
+ // name. Does not rely on function decomposition to work - if it
+ // doesn't debugging will be slightly less informative
+ // (i.e. toString will say 'spy' rather than 'myFunc').
+ if (!name) {
+ var matches = func.toString().match(/function ([^\s\(]+)/);
+ name = matches && matches[1];
+ }
+
+ return name;
+ };
+
+ sinon.functionToString = function toString() {
+ if (this.getCall && this.callCount) {
+ var thisValue, prop, i = this.callCount;
+
+ while (i--) {
+ thisValue = this.getCall(i).thisValue;
+
+ for (prop in thisValue) {
+ if (thisValue[prop] === this) {
+ return prop;
+ }
+ }
+ }
+ }
+
+ return this.displayName || "sinon fake";
+ };
+
+ sinon.objectKeys = function objectKeys(obj) {
+ if (obj !== Object(obj)) {
+ throw new TypeError("sinon.objectKeys called on a non-object");
+ }
+
+ var keys = [];
+ var key;
+ for (key in obj) {
+ if (hasOwn.call(obj, key)) {
+ keys.push(key);
+ }
+ }
+
+ return keys;
+ };
+
+ sinon.getPropertyDescriptor = function getPropertyDescriptor(object, property) {
+ var proto = object, descriptor;
+ while (proto && !(descriptor = Object.getOwnPropertyDescriptor(proto, property))) {
+ proto = Object.getPrototypeOf(proto);
+ }
+ return descriptor;
+ }
+
+ sinon.getConfig = function (custom) {
+ var config = {};
+ custom = custom || {};
+ var defaults = sinon.defaultConfig;
+
+ for (var prop in defaults) {
+ if (defaults.hasOwnProperty(prop)) {
+ config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop];
+ }
+ }
+
+ return config;
+ };
+
+ sinon.defaultConfig = {
+ injectIntoThis: true,
+ injectInto: null,
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+ useFakeTimers: true,
+ useFakeServer: true
+ };
+
+ sinon.timesInWords = function timesInWords(count) {
+ return count == 1 && "once" ||
+ count == 2 && "twice" ||
+ count == 3 && "thrice" ||
+ (count || 0) + " times";
+ };
+
+ sinon.calledInOrder = function (spies) {
+ for (var i = 1, l = spies.length; i < l; i++) {
+ if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ sinon.orderByFirstCall = function (spies) {
+ return spies.sort(function (a, b) {
+ // uuid, won't ever be equal
+ var aCall = a.getCall(0);
+ var bCall = b.getCall(0);
+ var aId = aCall && aCall.callId || -1;
+ var bId = bCall && bCall.callId || -1;
+
+ return aId < bId ? -1 : 1;
+ });
+ };
+
+ sinon.createStubInstance = function (constructor) {
+ if (typeof constructor !== "function") {
+ throw new TypeError("The constructor should be a function.");
+ }
+ return sinon.stub(sinon.create(constructor.prototype));
+ };
+
+ sinon.restore = function (object) {
+ if (object !== null && typeof object === "object") {
+ for (var prop in object) {
+ if (isRestorable(object[prop])) {
+ object[prop].restore();
+ }
+ }
+ } else if (isRestorable(object)) {
+ object.restore();
+ }
+ };
+
+ return sinon;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports) {
+ makeApi(exports);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ */
+
+(function (sinon) {
+ function makeApi(sinon) {
+
+ // Adapted from https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
+ var hasDontEnumBug = (function () {
+ var obj = {
+ constructor: function () {
+ return "0";
+ },
+ toString: function () {
+ return "1";
+ },
+ valueOf: function () {
+ return "2";
+ },
+ toLocaleString: function () {
+ return "3";
+ },
+ prototype: function () {
+ return "4";
+ },
+ isPrototypeOf: function () {
+ return "5";
+ },
+ propertyIsEnumerable: function () {
+ return "6";
+ },
+ hasOwnProperty: function () {
+ return "7";
+ },
+ length: function () {
+ return "8";
+ },
+ unique: function () {
+ return "9"
+ }
+ };
+
+ var result = [];
+ for (var prop in obj) {
+ result.push(obj[prop]());
+ }
+ return result.join("") !== "0123456789";
+ })();
+
+ /* Public: Extend target in place with all (own) properties from sources in-order. Thus, last source will
+ * override properties in previous sources.
+ *
+ * target - The Object to extend
+ * sources - Objects to copy properties from.
+ *
+ * Returns the extended target
+ */
+ function extend(target /*, sources */) {
+ var sources = Array.prototype.slice.call(arguments, 1),
+ source, i, prop;
+
+ for (i = 0; i < sources.length; i++) {
+ source = sources[i];
+
+ for (prop in source) {
+ if (source.hasOwnProperty(prop)) {
+ target[prop] = source[prop];
+ }
+ }
+
+ // Make sure we copy (own) toString method even when in JScript with DontEnum bug
+ // See https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug
+ if (hasDontEnumBug && source.hasOwnProperty("toString") && source.toString !== target.toString) {
+ target.toString = source.toString;
+ }
+ }
+
+ return target;
+ };
+
+ sinon.extend = extend;
+ return sinon.extend;
+ }
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ module.exports = makeApi(sinon);
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ */
+
+(function (sinon) {
+ function makeApi(sinon) {
+
+ function timesInWords(count) {
+ switch (count) {
+ case 1:
+ return "once";
+ case 2:
+ return "twice";
+ case 3:
+ return "thrice";
+ default:
+ return (count || 0) + " times";
+ }
+ }
+
+ sinon.timesInWords = timesInWords;
+ return sinon.timesInWords;
+ }
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ module.exports = makeApi(sinon);
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ */
+/**
+ * Format functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2014 Christian Johansen
+ */
+
+(function (sinon, formatio) {
+ function makeApi(sinon) {
+ function typeOf(value) {
+ if (value === null) {
+ return "null";
+ } else if (value === undefined) {
+ return "undefined";
+ }
+ var string = Object.prototype.toString.call(value);
+ return string.substring(8, string.length - 1).toLowerCase();
+ };
+
+ sinon.typeOf = typeOf;
+ return sinon.typeOf;
+ }
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ module.exports = makeApi(sinon);
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(
+ (typeof sinon == "object" && sinon || null),
+ (typeof formatio == "object" && formatio)
+));
+
+/**
+ * @depend util/core.js
+ * @depend typeOf.js
+ */
+/*jslint eqeqeq: false, onevar: false, plusplus: false*/
+/*global module, require, sinon*/
+/**
+ * Match functions
+ *
+ * @author Maximilian Antoni (mail@maxantoni.de)
+ * @license BSD
+ *
+ * Copyright (c) 2012 Maximilian Antoni
+ */
+
+(function (sinon) {
+ function makeApi(sinon) {
+ function assertType(value, type, name) {
+ var actual = sinon.typeOf(value);
+ if (actual !== type) {
+ throw new TypeError("Expected type of " + name + " to be " +
+ type + ", but was " + actual);
+ }
+ }
+
+ var matcher = {
+ toString: function () {
+ return this.message;
+ }
+ };
+
+ function isMatcher(object) {
+ return matcher.isPrototypeOf(object);
+ }
+
+ function matchObject(expectation, actual) {
+ if (actual === null || actual === undefined) {
+ return false;
+ }
+ for (var key in expectation) {
+ if (expectation.hasOwnProperty(key)) {
+ var exp = expectation[key];
+ var act = actual[key];
+ if (match.isMatcher(exp)) {
+ if (!exp.test(act)) {
+ return false;
+ }
+ } else if (sinon.typeOf(exp) === "object") {
+ if (!matchObject(exp, act)) {
+ return false;
+ }
+ } else if (!sinon.deepEqual(exp, act)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ matcher.or = function (m2) {
+ if (!arguments.length) {
+ throw new TypeError("Matcher expected");
+ } else if (!isMatcher(m2)) {
+ m2 = match(m2);
+ }
+ var m1 = this;
+ var or = sinon.create(matcher);
+ or.test = function (actual) {
+ return m1.test(actual) || m2.test(actual);
+ };
+ or.message = m1.message + ".or(" + m2.message + ")";
+ return or;
+ };
+
+ matcher.and = function (m2) {
+ if (!arguments.length) {
+ throw new TypeError("Matcher expected");
+ } else if (!isMatcher(m2)) {
+ m2 = match(m2);
+ }
+ var m1 = this;
+ var and = sinon.create(matcher);
+ and.test = function (actual) {
+ return m1.test(actual) && m2.test(actual);
+ };
+ and.message = m1.message + ".and(" + m2.message + ")";
+ return and;
+ };
+
+ var match = function (expectation, message) {
+ var m = sinon.create(matcher);
+ var type = sinon.typeOf(expectation);
+ switch (type) {
+ case "object":
+ if (typeof expectation.test === "function") {
+ m.test = function (actual) {
+ return expectation.test(actual) === true;
+ };
+ m.message = "match(" + sinon.functionName(expectation.test) + ")";
+ return m;
+ }
+ var str = [];
+ for (var key in expectation) {
+ if (expectation.hasOwnProperty(key)) {
+ str.push(key + ": " + expectation[key]);
+ }
+ }
+ m.test = function (actual) {
+ return matchObject(expectation, actual);
+ };
+ m.message = "match(" + str.join(", ") + ")";
+ break;
+ case "number":
+ m.test = function (actual) {
+ return expectation == actual;
+ };
+ break;
+ case "string":
+ m.test = function (actual) {
+ if (typeof actual !== "string") {
+ return false;
+ }
+ return actual.indexOf(expectation) !== -1;
+ };
+ m.message = "match(\"" + expectation + "\")";
+ break;
+ case "regexp":
+ m.test = function (actual) {
+ if (typeof actual !== "string") {
+ return false;
+ }
+ return expectation.test(actual);
+ };
+ break;
+ case "function":
+ m.test = expectation;
+ if (message) {
+ m.message = message;
+ } else {
+ m.message = "match(" + sinon.functionName(expectation) + ")";
+ }
+ break;
+ default:
+ m.test = function (actual) {
+ return sinon.deepEqual(expectation, actual);
+ };
+ }
+ if (!m.message) {
+ m.message = "match(" + expectation + ")";
+ }
+ return m;
+ };
+
+ match.isMatcher = isMatcher;
+
+ match.any = match(function () {
+ return true;
+ }, "any");
+
+ match.defined = match(function (actual) {
+ return actual !== null && actual !== undefined;
+ }, "defined");
+
+ match.truthy = match(function (actual) {
+ return !!actual;
+ }, "truthy");
+
+ match.falsy = match(function (actual) {
+ return !actual;
+ }, "falsy");
+
+ match.same = function (expectation) {
+ return match(function (actual) {
+ return expectation === actual;
+ }, "same(" + expectation + ")");
+ };
+
+ match.typeOf = function (type) {
+ assertType(type, "string", "type");
+ return match(function (actual) {
+ return sinon.typeOf(actual) === type;
+ }, "typeOf(\"" + type + "\")");
+ };
+
+ match.instanceOf = function (type) {
+ assertType(type, "function", "type");
+ return match(function (actual) {
+ return actual instanceof type;
+ }, "instanceOf(" + sinon.functionName(type) + ")");
+ };
+
+ function createPropertyMatcher(propertyTest, messagePrefix) {
+ return function (property, value) {
+ assertType(property, "string", "property");
+ var onlyProperty = arguments.length === 1;
+ var message = messagePrefix + "(\"" + property + "\"";
+ if (!onlyProperty) {
+ message += ", " + value;
+ }
+ message += ")";
+ return match(function (actual) {
+ if (actual === undefined || actual === null ||
+ !propertyTest(actual, property)) {
+ return false;
+ }
+ return onlyProperty || sinon.deepEqual(value, actual[property]);
+ }, message);
+ };
+ }
+
+ match.has = createPropertyMatcher(function (actual, property) {
+ if (typeof actual === "object") {
+ return property in actual;
+ }
+ return actual[property] !== undefined;
+ }, "has");
+
+ match.hasOwn = createPropertyMatcher(function (actual, property) {
+ return actual.hasOwnProperty(property);
+ }, "hasOwn");
+
+ match.bool = match.typeOf("boolean");
+ match.number = match.typeOf("number");
+ match.string = match.typeOf("string");
+ match.object = match.typeOf("object");
+ match.func = match.typeOf("function");
+ match.array = match.typeOf("array");
+ match.regexp = match.typeOf("regexp");
+ match.date = match.typeOf("date");
+
+ sinon.match = match;
+ return match;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./typeOf");
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ */
+/**
+ * Format functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2014 Christian Johansen
+ */
+
+(function (sinon, formatio) {
+ function makeApi(sinon) {
+ function valueFormatter(value) {
+ return "" + value;
+ }
+
+ function getFormatioFormatter() {
+ var formatter = formatio.configure({
+ quoteStrings: false,
+ limitChildrenCount: 250
+ });
+
+ function format() {
+ return formatter.ascii.apply(formatter, arguments);
+ };
+
+ return format;
+ }
+
+ function getNodeFormatter(value) {
+ function format(value) {
+ return typeof value == "object" && value.toString === Object.prototype.toString ? util.inspect(value) : value;
+ };
+
+ try {
+ var util = require("util");
+ } catch (e) {
+ /* Node, but no util module - would be very old, but better safe than sorry */
+ }
+
+ return util ? format : valueFormatter;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function",
+ formatter;
+
+ if (isNode) {
+ try {
+ formatio = require("formatio");
+ } catch (e) {}
+ }
+
+ if (formatio) {
+ formatter = getFormatioFormatter()
+ } else if (isNode) {
+ formatter = getNodeFormatter();
+ } else {
+ formatter = valueFormatter;
+ }
+
+ sinon.format = formatter;
+ return sinon.format;
+ }
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ module.exports = makeApi(sinon);
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(
+ (typeof sinon == "object" && sinon || null),
+ (typeof formatio == "object" && formatio)
+));
+
+/**
+ * @depend util/core.js
+ * @depend match.js
+ * @depend format.js
+ */
+/**
+ * Spy calls
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Maximilian Antoni (mail@maxantoni.de)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ * Copyright (c) 2013 Maximilian Antoni
+ */
+
+(function (sinon) {
+ function makeApi(sinon) {
+ function throwYieldError(proxy, text, args) {
+ var msg = sinon.functionName(proxy) + text;
+ if (args.length) {
+ msg += " Received [" + slice.call(args).join(", ") + "]";
+ }
+ throw new Error(msg);
+ }
+
+ var slice = Array.prototype.slice;
+
+ var callProto = {
+ calledOn: function calledOn(thisValue) {
+ if (sinon.match && sinon.match.isMatcher(thisValue)) {
+ return thisValue.test(this.thisValue);
+ }
+ return this.thisValue === thisValue;
+ },
+
+ calledWith: function calledWith() {
+ var l = arguments.length;
+ if (l > this.args.length) {
+ return false;
+ }
+ for (var i = 0; i < l; i += 1) {
+ if (!sinon.deepEqual(arguments[i], this.args[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ calledWithMatch: function calledWithMatch() {
+ var l = arguments.length;
+ if (l > this.args.length) {
+ return false;
+ }
+ for (var i = 0; i < l; i += 1) {
+ var actual = this.args[i];
+ var expectation = arguments[i];
+ if (!sinon.match || !sinon.match(expectation).test(actual)) {
+ return false;
+ }
+ }
+ return true;
+ },
+
+ calledWithExactly: function calledWithExactly() {
+ return arguments.length == this.args.length &&
+ this.calledWith.apply(this, arguments);
+ },
+
+ notCalledWith: function notCalledWith() {
+ return !this.calledWith.apply(this, arguments);
+ },
+
+ notCalledWithMatch: function notCalledWithMatch() {
+ return !this.calledWithMatch.apply(this, arguments);
+ },
+
+ returned: function returned(value) {
+ return sinon.deepEqual(value, this.returnValue);
+ },
+
+ threw: function threw(error) {
+ if (typeof error === "undefined" || !this.exception) {
+ return !!this.exception;
+ }
+
+ return this.exception === error || this.exception.name === error;
+ },
+
+ calledWithNew: function calledWithNew() {
+ return this.proxy.prototype && this.thisValue instanceof this.proxy;
+ },
+
+ calledBefore: function (other) {
+ return this.callId < other.callId;
+ },
+
+ calledAfter: function (other) {
+ return this.callId > other.callId;
+ },
+
+ callArg: function (pos) {
+ this.args[pos]();
+ },
+
+ callArgOn: function (pos, thisValue) {
+ this.args[pos].apply(thisValue);
+ },
+
+ callArgWith: function (pos) {
+ this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1)));
+ },
+
+ callArgOnWith: function (pos, thisValue) {
+ var args = slice.call(arguments, 2);
+ this.args[pos].apply(thisValue, args);
+ },
+
+ yield: function () {
+ this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0)));
+ },
+
+ yieldOn: function (thisValue) {
+ var args = this.args;
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (typeof args[i] === "function") {
+ args[i].apply(thisValue, slice.call(arguments, 1));
+ return;
+ }
+ }
+ throwYieldError(this.proxy, " cannot yield since no callback was passed.", args);
+ },
+
+ yieldTo: function (prop) {
+ this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1)));
+ },
+
+ yieldToOn: function (prop, thisValue) {
+ var args = this.args;
+ for (var i = 0, l = args.length; i < l; ++i) {
+ if (args[i] && typeof args[i][prop] === "function") {
+ args[i][prop].apply(thisValue, slice.call(arguments, 2));
+ return;
+ }
+ }
+ throwYieldError(this.proxy, " cannot yield to '" + prop +
+ "' since no callback was passed.", args);
+ },
+
+ toString: function () {
+ var callStr = this.proxy.toString() + "(";
+ var args = [];
+
+ for (var i = 0, l = this.args.length; i < l; ++i) {
+ args.push(sinon.format(this.args[i]));
+ }
+
+ callStr = callStr + args.join(", ") + ")";
+
+ if (typeof this.returnValue != "undefined") {
+ callStr += " => " + sinon.format(this.returnValue);
+ }
+
+ if (this.exception) {
+ callStr += " !" + this.exception.name;
+
+ if (this.exception.message) {
+ callStr += "(" + this.exception.message + ")";
+ }
+ }
+
+ return callStr;
+ }
+ };
+
+ callProto.invokeCallback = callProto.yield;
+
+ function createSpyCall(spy, thisValue, args, returnValue, exception, id) {
+ if (typeof id !== "number") {
+ throw new TypeError("Call id is not a number");
+ }
+ var proxyCall = sinon.create(callProto);
+ proxyCall.proxy = spy;
+ proxyCall.thisValue = thisValue;
+ proxyCall.args = args;
+ proxyCall.returnValue = returnValue;
+ proxyCall.exception = exception;
+ proxyCall.callId = id;
+
+ return proxyCall;
+ }
+ createSpyCall.toString = callProto.toString; // used by mocks
+
+ sinon.spyCall = createSpyCall;
+ return createSpyCall;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./match");
+ require("./format");
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend times_in_words.js
+ * @depend util/core.js
+ * @depend extend.js
+ * @depend call.js
+ * @depend format.js
+ */
+/**
+ * Spy functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+
+ function makeApi(sinon) {
+ var push = Array.prototype.push;
+ var slice = Array.prototype.slice;
+ var callId = 0;
+
+ function spy(object, property, types) {
+ if (!property && typeof object == "function") {
+ return spy.create(object);
+ }
+
+ if (!object && !property) {
+ return spy.create(function () { });
+ }
+
+ if (types) {
+ var methodDesc = sinon.getPropertyDescriptor(object, property);
+ for (var i = 0; i < types.length; i++) {
+ methodDesc[types[i]] = spy.create(methodDesc[types[i]]);
+ }
+ return sinon.wrapMethod(object, property, methodDesc);
+ } else {
+ var method = object[property];
+ return sinon.wrapMethod(object, property, spy.create(method));
+ }
+ }
+
+ function matchingFake(fakes, args, strict) {
+ if (!fakes) {
+ return;
+ }
+
+ for (var i = 0, l = fakes.length; i < l; i++) {
+ if (fakes[i].matches(args, strict)) {
+ return fakes[i];
+ }
+ }
+ }
+
+ function incrementCallCount() {
+ this.called = true;
+ this.callCount += 1;
+ this.notCalled = false;
+ this.calledOnce = this.callCount == 1;
+ this.calledTwice = this.callCount == 2;
+ this.calledThrice = this.callCount == 3;
+ }
+
+ function createCallProperties() {
+ this.firstCall = this.getCall(0);
+ this.secondCall = this.getCall(1);
+ this.thirdCall = this.getCall(2);
+ this.lastCall = this.getCall(this.callCount - 1);
+ }
+
+ var vars = "a,b,c,d,e,f,g,h,i,j,k,l";
+ function createProxy(func, proxyLength) {
+ // Retain the function length:
+ var p;
+ if (proxyLength) {
+ eval("p = (function proxy(" + vars.substring(0, proxyLength * 2 - 1) +
+ ") { return p.invoke(func, this, slice.call(arguments)); });");
+ } else {
+ p = function proxy() {
+ return p.invoke(func, this, slice.call(arguments));
+ };
+ }
+ p.isSinonProxy = true;
+ return p;
+ }
+
+ var uuid = 0;
+
+ // Public API
+ var spyApi = {
+ reset: function () {
+ if (this.invoking) {
+ var err = new Error("Cannot reset Sinon function while invoking it. " +
+ "Move the call to .reset outside of the callback.");
+ err.name = "InvalidResetException";
+ throw err;
+ }
+
+ this.called = false;
+ this.notCalled = true;
+ this.calledOnce = false;
+ this.calledTwice = false;
+ this.calledThrice = false;
+ this.callCount = 0;
+ this.firstCall = null;
+ this.secondCall = null;
+ this.thirdCall = null;
+ this.lastCall = null;
+ this.args = [];
+ this.returnValues = [];
+ this.thisValues = [];
+ this.exceptions = [];
+ this.callIds = [];
+ if (this.fakes) {
+ for (var i = 0; i < this.fakes.length; i++) {
+ this.fakes[i].reset();
+ }
+ }
+
+ return this;
+ },
+
+ create: function create(func, spyLength) {
+ var name;
+
+ if (typeof func != "function") {
+ func = function () { };
+ } else {
+ name = sinon.functionName(func);
+ }
+
+ if (!spyLength) {
+ spyLength = func.length;
+ }
+
+ var proxy = createProxy(func, spyLength);
+
+ sinon.extend(proxy, spy);
+ delete proxy.create;
+ sinon.extend(proxy, func);
+
+ proxy.reset();
+ proxy.prototype = func.prototype;
+ proxy.displayName = name || "spy";
+ proxy.toString = sinon.functionToString;
+ proxy.instantiateFake = sinon.spy.create;
+ proxy.id = "spy#" + uuid++;
+
+ return proxy;
+ },
+
+ invoke: function invoke(func, thisValue, args) {
+ var matching = matchingFake(this.fakes, args);
+ var exception, returnValue;
+
+ incrementCallCount.call(this);
+ push.call(this.thisValues, thisValue);
+ push.call(this.args, args);
+ push.call(this.callIds, callId++);
+
+ // Make call properties available from within the spied function:
+ createCallProperties.call(this);
+
+ try {
+ this.invoking = true;
+
+ if (matching) {
+ returnValue = matching.invoke(func, thisValue, args);
+ } else {
+ returnValue = (this.func || func).apply(thisValue, args);
+ }
+
+ var thisCall = this.getCall(this.callCount - 1);
+ if (thisCall.calledWithNew() && typeof returnValue !== "object") {
+ returnValue = thisValue;
+ }
+ } catch (e) {
+ exception = e;
+ } finally {
+ delete this.invoking;
+ }
+
+ push.call(this.exceptions, exception);
+ push.call(this.returnValues, returnValue);
+
+ // Make return value and exception available in the calls:
+ createCallProperties.call(this);
+
+ if (exception !== undefined) {
+ throw exception;
+ }
+
+ return returnValue;
+ },
+
+ named: function named(name) {
+ this.displayName = name;
+ return this;
+ },
+
+ getCall: function getCall(i) {
+ if (i < 0 || i >= this.callCount) {
+ return null;
+ }
+
+ return sinon.spyCall(this, this.thisValues[i], this.args[i],
+ this.returnValues[i], this.exceptions[i],
+ this.callIds[i]);
+ },
+
+ getCalls: function () {
+ var calls = [];
+ var i;
+
+ for (i = 0; i < this.callCount; i++) {
+ calls.push(this.getCall(i));
+ }
+
+ return calls;
+ },
+
+ calledBefore: function calledBefore(spyFn) {
+ if (!this.called) {
+ return false;
+ }
+
+ if (!spyFn.called) {
+ return true;
+ }
+
+ return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1];
+ },
+
+ calledAfter: function calledAfter(spyFn) {
+ if (!this.called || !spyFn.called) {
+ return false;
+ }
+
+ return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1];
+ },
+
+ withArgs: function () {
+ var args = slice.call(arguments);
+
+ if (this.fakes) {
+ var match = matchingFake(this.fakes, args, true);
+
+ if (match) {
+ return match;
+ }
+ } else {
+ this.fakes = [];
+ }
+
+ var original = this;
+ var fake = this.instantiateFake();
+ fake.matchingAguments = args;
+ fake.parent = this;
+ push.call(this.fakes, fake);
+
+ fake.withArgs = function () {
+ return original.withArgs.apply(original, arguments);
+ };
+
+ for (var i = 0; i < this.args.length; i++) {
+ if (fake.matches(this.args[i])) {
+ incrementCallCount.call(fake);
+ push.call(fake.thisValues, this.thisValues[i]);
+ push.call(fake.args, this.args[i]);
+ push.call(fake.returnValues, this.returnValues[i]);
+ push.call(fake.exceptions, this.exceptions[i]);
+ push.call(fake.callIds, this.callIds[i]);
+ }
+ }
+ createCallProperties.call(fake);
+
+ return fake;
+ },
+
+ matches: function (args, strict) {
+ var margs = this.matchingAguments;
+
+ if (margs.length <= args.length &&
+ sinon.deepEqual(margs, args.slice(0, margs.length))) {
+ return !strict || margs.length == args.length;
+ }
+ },
+
+ printf: function (format) {
+ var spy = this;
+ var args = slice.call(arguments, 1);
+ var formatter;
+
+ return (format || "").replace(/%(.)/g, function (match, specifyer) {
+ formatter = spyApi.formatters[specifyer];
+
+ if (typeof formatter == "function") {
+ return formatter.call(null, spy, args);
+ } else if (!isNaN(parseInt(specifyer, 10))) {
+ return sinon.format(args[specifyer - 1]);
+ }
+
+ return "%" + specifyer;
+ });
+ }
+ };
+
+ function delegateToCalls(method, matchAny, actual, notCalled) {
+ spyApi[method] = function () {
+ if (!this.called) {
+ if (notCalled) {
+ return notCalled.apply(this, arguments);
+ }
+ return false;
+ }
+
+ var currentCall;
+ var matches = 0;
+
+ for (var i = 0, l = this.callCount; i < l; i += 1) {
+ currentCall = this.getCall(i);
+
+ if (currentCall[actual || method].apply(currentCall, arguments)) {
+ matches += 1;
+
+ if (matchAny) {
+ return true;
+ }
+ }
+ }
+
+ return matches === this.callCount;
+ };
+ }
+
+ delegateToCalls("calledOn", true);
+ delegateToCalls("alwaysCalledOn", false, "calledOn");
+ delegateToCalls("calledWith", true);
+ delegateToCalls("calledWithMatch", true);
+ delegateToCalls("alwaysCalledWith", false, "calledWith");
+ delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch");
+ delegateToCalls("calledWithExactly", true);
+ delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly");
+ delegateToCalls("neverCalledWith", false, "notCalledWith", function () {
+ return true;
+ });
+ delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch", function () {
+ return true;
+ });
+ delegateToCalls("threw", true);
+ delegateToCalls("alwaysThrew", false, "threw");
+ delegateToCalls("returned", true);
+ delegateToCalls("alwaysReturned", false, "returned");
+ delegateToCalls("calledWithNew", true);
+ delegateToCalls("alwaysCalledWithNew", false, "calledWithNew");
+ delegateToCalls("callArg", false, "callArgWith", function () {
+ throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+ });
+ spyApi.callArgWith = spyApi.callArg;
+ delegateToCalls("callArgOn", false, "callArgOnWith", function () {
+ throw new Error(this.toString() + " cannot call arg since it was not yet invoked.");
+ });
+ spyApi.callArgOnWith = spyApi.callArgOn;
+ delegateToCalls("yield", false, "yield", function () {
+ throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+ });
+ // "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode.
+ spyApi.invokeCallback = spyApi.yield;
+ delegateToCalls("yieldOn", false, "yieldOn", function () {
+ throw new Error(this.toString() + " cannot yield since it was not yet invoked.");
+ });
+ delegateToCalls("yieldTo", false, "yieldTo", function (property) {
+ throw new Error(this.toString() + " cannot yield to '" + property +
+ "' since it was not yet invoked.");
+ });
+ delegateToCalls("yieldToOn", false, "yieldToOn", function (property) {
+ throw new Error(this.toString() + " cannot yield to '" + property +
+ "' since it was not yet invoked.");
+ });
+
+ spyApi.formatters = {
+ c: function (spy) {
+ return sinon.timesInWords(spy.callCount);
+ },
+
+ n: function (spy) {
+ return spy.toString();
+ },
+
+ C: function (spy) {
+ var calls = [];
+
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
+ var stringifiedCall = " " + spy.getCall(i).toString();
+ if (/\n/.test(calls[i - 1])) {
+ stringifiedCall = "\n" + stringifiedCall;
+ }
+ push.call(calls, stringifiedCall);
+ }
+
+ return calls.length > 0 ? "\n" + calls.join("\n") : "";
+ },
+
+ t: function (spy) {
+ var objects = [];
+
+ for (var i = 0, l = spy.callCount; i < l; ++i) {
+ push.call(objects, sinon.format(spy.thisValues[i]));
+ }
+
+ return objects.join(", ");
+ },
+
+ "*": function (spy, args) {
+ var formatted = [];
+
+ for (var i = 0, l = args.length; i < l; ++i) {
+ push.call(formatted, sinon.format(args[i]));
+ }
+
+ return formatted.join(", ");
+ }
+ };
+
+ sinon.extend(spy, spyApi);
+
+ spy.spyCall = sinon.spyCall;
+ sinon.spy = spy;
+
+ return spy;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./call");
+ require("./extend");
+ require("./times_in_words");
+ require("./format");
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ * @depend extend.js
+ */
+/**
+ * Stub behavior
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @author Tim Fischbach (mail@timfischbach.de)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ var slice = Array.prototype.slice;
+ var join = Array.prototype.join;
+ var useLeftMostCallback = -1;
+ var useRightMostCallback = -2;
+
+ var nextTick = (function () {
+ if (typeof process === "object" && typeof process.nextTick === "function") {
+ return process.nextTick;
+ } else if (typeof setImmediate === "function") {
+ return setImmediate;
+ } else {
+ return function (callback) {
+ setTimeout(callback, 0);
+ };
+ }
+ })();
+
+ function throwsException(error, message) {
+ if (typeof error == "string") {
+ this.exception = new Error(message || "");
+ this.exception.name = error;
+ } else if (!error) {
+ this.exception = new Error("Error");
+ } else {
+ this.exception = error;
+ }
+
+ return this;
+ }
+
+ function getCallback(behavior, args) {
+ var callArgAt = behavior.callArgAt;
+
+ if (callArgAt >= 0) {
+ return args[callArgAt];
+ }
+
+ var argumentList;
+
+ if (callArgAt === useLeftMostCallback) {
+ argumentList = args;
+ }
+
+ if (callArgAt === useRightMostCallback) {
+ argumentList = slice.call(args).reverse();
+ }
+
+ var callArgProp = behavior.callArgProp;
+
+ for (var i = 0, l = argumentList.length; i < l; ++i) {
+ if (!callArgProp && typeof argumentList[i] == "function") {
+ return argumentList[i];
+ }
+
+ if (callArgProp && argumentList[i] &&
+ typeof argumentList[i][callArgProp] == "function") {
+ return argumentList[i][callArgProp];
+ }
+ }
+
+ return null;
+ }
+
+ function makeApi(sinon) {
+ function getCallbackError(behavior, func, args) {
+ if (behavior.callArgAt < 0) {
+ var msg;
+
+ if (behavior.callArgProp) {
+ msg = sinon.functionName(behavior.stub) +
+ " expected to yield to '" + behavior.callArgProp +
+ "', but no object with such a property was passed.";
+ } else {
+ msg = sinon.functionName(behavior.stub) +
+ " expected to yield, but no callback was passed.";
+ }
+
+ if (args.length > 0) {
+ msg += " Received [" + join.call(args, ", ") + "]";
+ }
+
+ return msg;
+ }
+
+ return "argument at index " + behavior.callArgAt + " is not a function: " + func;
+ }
+
+ function callCallback(behavior, args) {
+ if (typeof behavior.callArgAt == "number") {
+ var func = getCallback(behavior, args);
+
+ if (typeof func != "function") {
+ throw new TypeError(getCallbackError(behavior, func, args));
+ }
+
+ if (behavior.callbackAsync) {
+ nextTick(function () {
+ func.apply(behavior.callbackContext, behavior.callbackArguments);
+ });
+ } else {
+ func.apply(behavior.callbackContext, behavior.callbackArguments);
+ }
+ }
+ }
+
+ var proto = {
+ create: function create(stub) {
+ var behavior = sinon.extend({}, sinon.behavior);
+ delete behavior.create;
+ behavior.stub = stub;
+
+ return behavior;
+ },
+
+ isPresent: function isPresent() {
+ return (typeof this.callArgAt == "number" ||
+ this.exception ||
+ typeof this.returnArgAt == "number" ||
+ this.returnThis ||
+ this.returnValueDefined);
+ },
+
+ invoke: function invoke(context, args) {
+ callCallback(this, args);
+
+ if (this.exception) {
+ throw this.exception;
+ } else if (typeof this.returnArgAt == "number") {
+ return args[this.returnArgAt];
+ } else if (this.returnThis) {
+ return context;
+ }
+
+ return this.returnValue;
+ },
+
+ onCall: function onCall(index) {
+ return this.stub.onCall(index);
+ },
+
+ onFirstCall: function onFirstCall() {
+ return this.stub.onFirstCall();
+ },
+
+ onSecondCall: function onSecondCall() {
+ return this.stub.onSecondCall();
+ },
+
+ onThirdCall: function onThirdCall() {
+ return this.stub.onThirdCall();
+ },
+
+ withArgs: function withArgs(/* arguments */) {
+ throw new Error("Defining a stub by invoking \"stub.onCall(...).withArgs(...)\" is not supported. " +
+ "Use \"stub.withArgs(...).onCall(...)\" to define sequential behavior for calls with certain arguments.");
+ },
+
+ callsArg: function callsArg(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = [];
+ this.callbackContext = undefined;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ callsArgOn: function callsArgOn(pos, context) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = [];
+ this.callbackContext = context;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ callsArgWith: function callsArgWith(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = slice.call(arguments, 1);
+ this.callbackContext = undefined;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ callsArgOnWith: function callsArgWith(pos, context) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = pos;
+ this.callbackArguments = slice.call(arguments, 2);
+ this.callbackContext = context;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ yields: function () {
+ this.callArgAt = useLeftMostCallback;
+ this.callbackArguments = slice.call(arguments, 0);
+ this.callbackContext = undefined;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ yieldsRight: function () {
+ this.callArgAt = useRightMostCallback;
+ this.callbackArguments = slice.call(arguments, 0);
+ this.callbackContext = undefined;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ yieldsOn: function (context) {
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = useLeftMostCallback;
+ this.callbackArguments = slice.call(arguments, 1);
+ this.callbackContext = context;
+ this.callArgProp = undefined;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ yieldsTo: function (prop) {
+ this.callArgAt = useLeftMostCallback;
+ this.callbackArguments = slice.call(arguments, 1);
+ this.callbackContext = undefined;
+ this.callArgProp = prop;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ yieldsToOn: function (prop, context) {
+ if (typeof context != "object") {
+ throw new TypeError("argument context is not an object");
+ }
+
+ this.callArgAt = useLeftMostCallback;
+ this.callbackArguments = slice.call(arguments, 2);
+ this.callbackContext = context;
+ this.callArgProp = prop;
+ this.callbackAsync = false;
+
+ return this;
+ },
+
+ throws: throwsException,
+ throwsException: throwsException,
+
+ returns: function returns(value) {
+ this.returnValue = value;
+ this.returnValueDefined = true;
+
+ return this;
+ },
+
+ returnsArg: function returnsArg(pos) {
+ if (typeof pos != "number") {
+ throw new TypeError("argument index is not number");
+ }
+
+ this.returnArgAt = pos;
+
+ return this;
+ },
+
+ returnsThis: function returnsThis() {
+ this.returnThis = true;
+
+ return this;
+ }
+ };
+
+ // create asynchronous versions of callsArg* and yields* methods
+ for (var method in proto) {
+ // need to avoid creating anotherasync versions of the newly added async methods
+ if (proto.hasOwnProperty(method) &&
+ method.match(/^(callsArg|yields)/) &&
+ !method.match(/Async/)) {
+ proto[method + "Async"] = (function (syncFnName) {
+ return function () {
+ var result = this[syncFnName].apply(this, arguments);
+ this.callbackAsync = true;
+ return result;
+ };
+ })(method);
+ }
+ }
+
+ sinon.behavior = proto;
+ return proto;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./extend");
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ * @depend extend.js
+ * @depend spy.js
+ * @depend behavior.js
+ */
+/**
+ * Stub functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ function makeApi(sinon) {
+ function stub(object, property, func) {
+ if (!!func && typeof func != "function" && typeof func != "object") {
+ throw new TypeError("Custom stub should be a function or a property descriptor");
+ }
+
+ var wrapper;
+
+ if (func) {
+ if (typeof func == "function") {
+ wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func;
+ } else {
+ wrapper = func;
+ if (sinon.spy && sinon.spy.create) {
+ var types = sinon.objectKeys(wrapper);
+ for (var i = 0; i < types.length; i++) {
+ wrapper[types[i]] = sinon.spy.create(wrapper[types[i]]);
+ }
+ }
+ }
+ } else {
+ var stubLength = 0;
+ if (typeof object == "object" && typeof object[property] == "function") {
+ stubLength = object[property].length;
+ }
+ wrapper = stub.create(stubLength);
+ }
+
+ if (!object && typeof property === "undefined") {
+ return sinon.stub.create();
+ }
+
+ if (typeof property === "undefined" && typeof object == "object") {
+ for (var prop in object) {
+ if (typeof sinon.getPropertyDescriptor(object, prop).value === "function") {
+ stub(object, prop);
+ }
+ }
+
+ return object;
+ }
+
+ return sinon.wrapMethod(object, property, wrapper);
+ }
+
+ function getDefaultBehavior(stub) {
+ return stub.defaultBehavior || getParentBehaviour(stub) || sinon.behavior.create(stub);
+ }
+
+ function getParentBehaviour(stub) {
+ return (stub.parent && getCurrentBehavior(stub.parent));
+ }
+
+ function getCurrentBehavior(stub) {
+ var behavior = stub.behaviors[stub.callCount - 1];
+ return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stub);
+ }
+
+ var uuid = 0;
+
+ var proto = {
+ create: function create(stubLength) {
+ var functionStub = function () {
+ return getCurrentBehavior(functionStub).invoke(this, arguments);
+ };
+
+ functionStub.id = "stub#" + uuid++;
+ var orig = functionStub;
+ functionStub = sinon.spy.create(functionStub, stubLength);
+ functionStub.func = orig;
+
+ sinon.extend(functionStub, stub);
+ functionStub.instantiateFake = sinon.stub.create;
+ functionStub.displayName = "stub";
+ functionStub.toString = sinon.functionToString;
+
+ functionStub.defaultBehavior = null;
+ functionStub.behaviors = [];
+
+ return functionStub;
+ },
+
+ resetBehavior: function () {
+ var i;
+
+ this.defaultBehavior = null;
+ this.behaviors = [];
+
+ delete this.returnValue;
+ delete this.returnArgAt;
+ this.returnThis = false;
+
+ if (this.fakes) {
+ for (i = 0; i < this.fakes.length; i++) {
+ this.fakes[i].resetBehavior();
+ }
+ }
+ },
+
+ onCall: function onCall(index) {
+ if (!this.behaviors[index]) {
+ this.behaviors[index] = sinon.behavior.create(this);
+ }
+
+ return this.behaviors[index];
+ },
+
+ onFirstCall: function onFirstCall() {
+ return this.onCall(0);
+ },
+
+ onSecondCall: function onSecondCall() {
+ return this.onCall(1);
+ },
+
+ onThirdCall: function onThirdCall() {
+ return this.onCall(2);
+ }
+ };
+
+ for (var method in sinon.behavior) {
+ if (sinon.behavior.hasOwnProperty(method) &&
+ !proto.hasOwnProperty(method) &&
+ method != "create" &&
+ method != "withArgs" &&
+ method != "invoke") {
+ proto[method] = (function (behaviorMethod) {
+ return function () {
+ this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this);
+ this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments);
+ return this;
+ };
+ }(method));
+ }
+ }
+
+ sinon.extend(stub, proto);
+ sinon.stub = stub;
+
+ return stub;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./behavior");
+ require("./spy");
+ require("./extend");
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend times_in_words.js
+ * @depend util/core.js
+ * @depend call.js
+ * @depend extend.js
+ * @depend match.js
+ * @depend spy.js
+ * @depend stub.js
+ * @depend format.js
+ */
+/**
+ * Mock functions.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ function makeApi(sinon) {
+ var push = [].push;
+ var match = sinon.match;
+
+ function mock(object) {
+ // if (typeof console !== undefined && console.warn) {
+ // console.warn("mock will be removed from Sinon.JS v2.0");
+ // }
+
+ if (!object) {
+ return sinon.expectation.create("Anonymous mock");
+ }
+
+ return mock.create(object);
+ }
+
+ function each(collection, callback) {
+ if (!collection) {
+ return;
+ }
+
+ for (var i = 0, l = collection.length; i < l; i += 1) {
+ callback(collection[i]);
+ }
+ }
+
+ sinon.extend(mock, {
+ create: function create(object) {
+ if (!object) {
+ throw new TypeError("object is null");
+ }
+
+ var mockObject = sinon.extend({}, mock);
+ mockObject.object = object;
+ delete mockObject.create;
+
+ return mockObject;
+ },
+
+ expects: function expects(method) {
+ if (!method) {
+ throw new TypeError("method is falsy");
+ }
+
+ if (!this.expectations) {
+ this.expectations = {};
+ this.proxies = [];
+ }
+
+ if (!this.expectations[method]) {
+ this.expectations[method] = [];
+ var mockObject = this;
+
+ sinon.wrapMethod(this.object, method, function () {
+ return mockObject.invokeMethod(method, this, arguments);
+ });
+
+ push.call(this.proxies, method);
+ }
+
+ var expectation = sinon.expectation.create(method);
+ push.call(this.expectations[method], expectation);
+
+ return expectation;
+ },
+
+ restore: function restore() {
+ var object = this.object;
+
+ each(this.proxies, function (proxy) {
+ if (typeof object[proxy].restore == "function") {
+ object[proxy].restore();
+ }
+ });
+ },
+
+ verify: function verify() {
+ var expectations = this.expectations || {};
+ var messages = [], met = [];
+
+ each(this.proxies, function (proxy) {
+ each(expectations[proxy], function (expectation) {
+ if (!expectation.met()) {
+ push.call(messages, expectation.toString());
+ } else {
+ push.call(met, expectation.toString());
+ }
+ });
+ });
+
+ this.restore();
+
+ if (messages.length > 0) {
+ sinon.expectation.fail(messages.concat(met).join("\n"));
+ } else if (met.length > 0) {
+ sinon.expectation.pass(messages.concat(met).join("\n"));
+ }
+
+ return true;
+ },
+
+ invokeMethod: function invokeMethod(method, thisValue, args) {
+ var expectations = this.expectations && this.expectations[method];
+ var length = expectations && expectations.length || 0, i;
+
+ for (i = 0; i < length; i += 1) {
+ if (!expectations[i].met() &&
+ expectations[i].allowsCall(thisValue, args)) {
+ return expectations[i].apply(thisValue, args);
+ }
+ }
+
+ var messages = [], available, exhausted = 0;
+
+ for (i = 0; i < length; i += 1) {
+ if (expectations[i].allowsCall(thisValue, args)) {
+ available = available || expectations[i];
+ } else {
+ exhausted += 1;
+ }
+ push.call(messages, " " + expectations[i].toString());
+ }
+
+ if (exhausted === 0) {
+ return available.apply(thisValue, args);
+ }
+
+ messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({
+ proxy: method,
+ args: args
+ }));
+
+ sinon.expectation.fail(messages.join("\n"));
+ }
+ });
+
+ var times = sinon.timesInWords;
+ var slice = Array.prototype.slice;
+
+ function callCountInWords(callCount) {
+ if (callCount == 0) {
+ return "never called";
+ } else {
+ return "called " + times(callCount);
+ }
+ }
+
+ function expectedCallCountInWords(expectation) {
+ var min = expectation.minCalls;
+ var max = expectation.maxCalls;
+
+ if (typeof min == "number" && typeof max == "number") {
+ var str = times(min);
+
+ if (min != max) {
+ str = "at least " + str + " and at most " + times(max);
+ }
+
+ return str;
+ }
+
+ if (typeof min == "number") {
+ return "at least " + times(min);
+ }
+
+ return "at most " + times(max);
+ }
+
+ function receivedMinCalls(expectation) {
+ var hasMinLimit = typeof expectation.minCalls == "number";
+ return !hasMinLimit || expectation.callCount >= expectation.minCalls;
+ }
+
+ function receivedMaxCalls(expectation) {
+ if (typeof expectation.maxCalls != "number") {
+ return false;
+ }
+
+ return expectation.callCount == expectation.maxCalls;
+ }
+
+ function verifyMatcher(possibleMatcher, arg) {
+ if (match && match.isMatcher(possibleMatcher)) {
+ return possibleMatcher.test(arg);
+ } else {
+ return true;
+ }
+ }
+
+ sinon.expectation = {
+ minCalls: 1,
+ maxCalls: 1,
+
+ create: function create(methodName) {
+ var expectation = sinon.extend(sinon.stub.create(), sinon.expectation);
+ delete expectation.create;
+ expectation.method = methodName;
+
+ return expectation;
+ },
+
+ invoke: function invoke(func, thisValue, args) {
+ this.verifyCallAllowed(thisValue, args);
+
+ return sinon.spy.invoke.apply(this, arguments);
+ },
+
+ atLeast: function atLeast(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not number");
+ }
+
+ if (!this.limitsSet) {
+ this.maxCalls = null;
+ this.limitsSet = true;
+ }
+
+ this.minCalls = num;
+
+ return this;
+ },
+
+ atMost: function atMost(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not number");
+ }
+
+ if (!this.limitsSet) {
+ this.minCalls = null;
+ this.limitsSet = true;
+ }
+
+ this.maxCalls = num;
+
+ return this;
+ },
+
+ never: function never() {
+ return this.exactly(0);
+ },
+
+ once: function once() {
+ return this.exactly(1);
+ },
+
+ twice: function twice() {
+ return this.exactly(2);
+ },
+
+ thrice: function thrice() {
+ return this.exactly(3);
+ },
+
+ exactly: function exactly(num) {
+ if (typeof num != "number") {
+ throw new TypeError("'" + num + "' is not a number");
+ }
+
+ this.atLeast(num);
+ return this.atMost(num);
+ },
+
+ met: function met() {
+ return !this.failed && receivedMinCalls(this);
+ },
+
+ verifyCallAllowed: function verifyCallAllowed(thisValue, args) {
+ if (receivedMaxCalls(this)) {
+ this.failed = true;
+ sinon.expectation.fail(this.method + " already called " + times(this.maxCalls));
+ }
+
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
+ sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " +
+ this.expectedThis);
+ }
+
+ if (!("expectedArguments" in this)) {
+ return;
+ }
+
+ if (!args) {
+ sinon.expectation.fail(this.method + " received no arguments, expected " +
+ sinon.format(this.expectedArguments));
+ }
+
+ if (args.length < this.expectedArguments.length) {
+ sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) +
+ "), expected " + sinon.format(this.expectedArguments));
+ }
+
+ if (this.expectsExactArgCount &&
+ args.length != this.expectedArguments.length) {
+ sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) +
+ "), expected " + sinon.format(this.expectedArguments));
+ }
+
+ for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+
+ if (!verifyMatcher(this.expectedArguments[i], args[i])) {
+ sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
+ ", didn't match " + this.expectedArguments.toString());
+ }
+
+ if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+ sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) +
+ ", expected " + sinon.format(this.expectedArguments));
+ }
+ }
+ },
+
+ allowsCall: function allowsCall(thisValue, args) {
+ if (this.met() && receivedMaxCalls(this)) {
+ return false;
+ }
+
+ if ("expectedThis" in this && this.expectedThis !== thisValue) {
+ return false;
+ }
+
+ if (!("expectedArguments" in this)) {
+ return true;
+ }
+
+ args = args || [];
+
+ if (args.length < this.expectedArguments.length) {
+ return false;
+ }
+
+ if (this.expectsExactArgCount &&
+ args.length != this.expectedArguments.length) {
+ return false;
+ }
+
+ for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) {
+ if (!verifyMatcher(this.expectedArguments[i], args[i])) {
+ return false;
+ }
+
+ if (!sinon.deepEqual(this.expectedArguments[i], args[i])) {
+ return false;
+ }
+ }
+
+ return true;
+ },
+
+ withArgs: function withArgs() {
+ this.expectedArguments = slice.call(arguments);
+ return this;
+ },
+
+ withExactArgs: function withExactArgs() {
+ this.withArgs.apply(this, arguments);
+ this.expectsExactArgCount = true;
+ return this;
+ },
+
+ on: function on(thisValue) {
+ this.expectedThis = thisValue;
+ return this;
+ },
+
+ toString: function () {
+ var args = (this.expectedArguments || []).slice();
+
+ if (!this.expectsExactArgCount) {
+ push.call(args, "[...]");
+ }
+
+ var callStr = sinon.spyCall.toString.call({
+ proxy: this.method || "anonymous mock expectation",
+ args: args
+ });
+
+ var message = callStr.replace(", [...", "[, ...") + " " +
+ expectedCallCountInWords(this);
+
+ if (this.met()) {
+ return "Expectation met: " + message;
+ }
+
+ return "Expected " + message + " (" +
+ callCountInWords(this.callCount) + ")";
+ },
+
+ verify: function verify() {
+ if (!this.met()) {
+ sinon.expectation.fail(this.toString());
+ } else {
+ sinon.expectation.pass(this.toString());
+ }
+
+ return true;
+ },
+
+ pass: function pass(message) {
+ sinon.assert.pass(message);
+ },
+
+ fail: function fail(message) {
+ var exception = new Error(message);
+ exception.name = "ExpectationError";
+
+ throw exception;
+ }
+ };
+
+ sinon.mock = mock;
+ return mock;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./times_in_words");
+ require("./call");
+ require("./extend");
+ require("./match");
+ require("./spy");
+ require("./stub");
+ require("./format");
+
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ * @depend spy.js
+ * @depend stub.js
+ * @depend mock.js
+ */
+/**
+ * Collections of stubs, spies and mocks.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ var push = [].push;
+ var hasOwnProperty = Object.prototype.hasOwnProperty;
+
+ function getFakes(fakeCollection) {
+ if (!fakeCollection.fakes) {
+ fakeCollection.fakes = [];
+ }
+
+ return fakeCollection.fakes;
+ }
+
+ function each(fakeCollection, method) {
+ var fakes = getFakes(fakeCollection);
+
+ for (var i = 0, l = fakes.length; i < l; i += 1) {
+ if (typeof fakes[i][method] == "function") {
+ fakes[i][method]();
+ }
+ }
+ }
+
+ function compact(fakeCollection) {
+ var fakes = getFakes(fakeCollection);
+ var i = 0;
+ while (i < fakes.length) {
+ fakes.splice(i, 1);
+ }
+ }
+
+ function makeApi(sinon) {
+ var collection = {
+ verify: function resolve() {
+ each(this, "verify");
+ },
+
+ restore: function restore() {
+ each(this, "restore");
+ compact(this);
+ },
+
+ reset: function restore() {
+ each(this, "reset");
+ },
+
+ verifyAndRestore: function verifyAndRestore() {
+ var exception;
+
+ try {
+ this.verify();
+ } catch (e) {
+ exception = e;
+ }
+
+ this.restore();
+
+ if (exception) {
+ throw exception;
+ }
+ },
+
+ add: function add(fake) {
+ push.call(getFakes(this), fake);
+ return fake;
+ },
+
+ spy: function spy() {
+ return this.add(sinon.spy.apply(sinon, arguments));
+ },
+
+ stub: function stub(object, property, value) {
+ if (property) {
+ var original = object[property];
+
+ if (typeof original != "function") {
+ if (!hasOwnProperty.call(object, property)) {
+ throw new TypeError("Cannot stub non-existent own property " + property);
+ }
+
+ object[property] = value;
+
+ return this.add({
+ restore: function () {
+ object[property] = original;
+ }
+ });
+ }
+ }
+ if (!property && !!object && typeof object == "object") {
+ var stubbedObj = sinon.stub.apply(sinon, arguments);
+
+ for (var prop in stubbedObj) {
+ if (typeof stubbedObj[prop] === "function") {
+ this.add(stubbedObj[prop]);
+ }
+ }
+
+ return stubbedObj;
+ }
+
+ return this.add(sinon.stub.apply(sinon, arguments));
+ },
+
+ mock: function mock() {
+ return this.add(sinon.mock.apply(sinon, arguments));
+ },
+
+ inject: function inject(obj) {
+ var col = this;
+
+ obj.spy = function () {
+ return col.spy.apply(col, arguments);
+ };
+
+ obj.stub = function () {
+ return col.stub.apply(col, arguments);
+ };
+
+ obj.mock = function () {
+ return col.mock.apply(col, arguments);
+ };
+
+ return obj;
+ }
+ };
+
+ sinon.collection = collection;
+ return collection;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./mock");
+ require("./spy");
+ require("./stub");
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/*global lolex */
+
+/**
+ * Fake timer API
+ * setTimeout
+ * setInterval
+ * clearTimeout
+ * clearInterval
+ * tick
+ * reset
+ * Date
+ *
+ * Inspired by jsUnitMockTimeOut from JsUnit
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ var sinon = {};
+}
+
+(function (global) {
+ function makeApi(sinon, lol) {
+ var llx = typeof lolex !== "undefined" ? lolex : lol;
+
+ sinon.useFakeTimers = function () {
+ var now, methods = Array.prototype.slice.call(arguments);
+
+ if (typeof methods[0] === "string") {
+ now = 0;
+ } else {
+ now = methods.shift();
+ }
+
+ var clock = llx.install(now || 0, methods);
+ clock.restore = clock.uninstall;
+ return clock;
+ };
+
+ sinon.clock = {
+ create: function (now) {
+ return llx.createClock(now);
+ }
+ };
+
+ sinon.timers = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined),
+ clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate : undefined),
+ setInterval: setInterval,
+ clearInterval: clearInterval,
+ Date: Date
+ };
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, epxorts, module, lolex) {
+ var sinon = require("./core");
+ makeApi(sinon, lolex);
+ module.exports = sinon;
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module, require("lolex"));
+ } else {
+ makeApi(sinon);
+ }
+}(typeof global != "undefined" && typeof global !== "function" ? global : this));
+
+/**
+ * Minimal Event interface implementation
+ *
+ * Original implementation by Sven Fuchs: https://gist.github.com/995028
+ * Modifications and tests by Christian Johansen.
+ *
+ * @author Sven Fuchs (svenfuchs@artweb-design.de)
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2011 Sven Fuchs, Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ this.sinon = {};
+}
+
+(function () {
+ var push = [].push;
+
+ function makeApi(sinon) {
+ sinon.Event = function Event(type, bubbles, cancelable, target) {
+ this.initEvent(type, bubbles, cancelable, target);
+ };
+
+ sinon.Event.prototype = {
+ initEvent: function (type, bubbles, cancelable, target) {
+ this.type = type;
+ this.bubbles = bubbles;
+ this.cancelable = cancelable;
+ this.target = target;
+ },
+
+ stopPropagation: function () {},
+
+ preventDefault: function () {
+ this.defaultPrevented = true;
+ }
+ };
+
+ sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) {
+ this.initEvent(type, false, false, target);
+ this.loaded = progressEventRaw.loaded || null;
+ this.total = progressEventRaw.total || null;
+ this.lengthComputable = !!progressEventRaw.total;
+ };
+
+ sinon.ProgressEvent.prototype = new sinon.Event();
+
+ sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent;
+
+ sinon.CustomEvent = function CustomEvent(type, customData, target) {
+ this.initEvent(type, false, false, target);
+ this.detail = customData.detail || null;
+ };
+
+ sinon.CustomEvent.prototype = new sinon.Event();
+
+ sinon.CustomEvent.prototype.constructor = sinon.CustomEvent;
+
+ sinon.EventTarget = {
+ addEventListener: function addEventListener(event, listener) {
+ this.eventListeners = this.eventListeners || {};
+ this.eventListeners[event] = this.eventListeners[event] || [];
+ push.call(this.eventListeners[event], listener);
+ },
+
+ removeEventListener: function removeEventListener(event, listener) {
+ var listeners = this.eventListeners && this.eventListeners[event] || [];
+
+ for (var i = 0, l = listeners.length; i < l; ++i) {
+ if (listeners[i] == listener) {
+ return listeners.splice(i, 1);
+ }
+ }
+ },
+
+ dispatchEvent: function dispatchEvent(event) {
+ var type = event.type;
+ var listeners = this.eventListeners && this.eventListeners[type] || [];
+
+ for (var i = 0; i < listeners.length; i++) {
+ if (typeof listeners[i] == "function") {
+ listeners[i].call(this, event);
+ } else {
+ listeners[i].handleEvent(event);
+ }
+ }
+
+ return !!event.defaultPrevented;
+ }
+ };
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require) {
+ var sinon = require("./core");
+ makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require);
+ } else {
+ makeApi(sinon);
+ }
+}());
+
+/**
+ * @depend util/core.js
+ */
+/**
+ * Logs errors
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2014 Christian Johansen
+ */
+
+(function (sinon) {
+ // cache a reference to setTimeout, so that our reference won't be stubbed out
+ // when using fake timers and errors will still get logged
+ // https://github.com/cjohansen/Sinon.JS/issues/381
+ var realSetTimeout = setTimeout;
+
+ function makeApi(sinon) {
+
+ function log() {}
+
+ function logError(label, err) {
+ var msg = label + " threw exception: ";
+
+ sinon.log(msg + "[" + err.name + "] " + err.message);
+
+ if (err.stack) {
+ sinon.log(err.stack);
+ }
+
+ logError.setTimeout(function () {
+ err.message = msg + err.message;
+ throw err;
+ }, 0);
+ };
+
+ // wrap realSetTimeout with something we can stub in tests
+ logError.setTimeout = function (func, timeout) {
+ realSetTimeout(func, timeout);
+ }
+
+ var exports = {};
+ exports.log = sinon.log = log;
+ exports.logError = sinon.logError = logError;
+
+ return exports;
+ }
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ module.exports = makeApi(sinon);
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend core.js
+ * @depend ../extend.js
+ * @depend event.js
+ * @depend ../log_error.js
+ */
+/**
+ * Fake XDomainRequest object
+ */
+
+if (typeof sinon == "undefined") {
+ this.sinon = {};
+}
+
+// wrapper for global
+(function (global) {
+ var xdr = { XDomainRequest: global.XDomainRequest };
+ xdr.GlobalXDomainRequest = global.XDomainRequest;
+ xdr.supportsXDR = typeof xdr.GlobalXDomainRequest != "undefined";
+ xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false;
+
+ function makeApi(sinon) {
+ sinon.xdr = xdr;
+
+ function FakeXDomainRequest() {
+ this.readyState = FakeXDomainRequest.UNSENT;
+ this.requestBody = null;
+ this.requestHeaders = {};
+ this.status = 0;
+ this.timeout = null;
+
+ if (typeof FakeXDomainRequest.onCreate == "function") {
+ FakeXDomainRequest.onCreate(this);
+ }
+ }
+
+ function verifyState(xdr) {
+ if (xdr.readyState !== FakeXDomainRequest.OPENED) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+
+ if (xdr.sendFlag) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+ }
+
+ function verifyRequestSent(xdr) {
+ if (xdr.readyState == FakeXDomainRequest.UNSENT) {
+ throw new Error("Request not sent");
+ }
+ if (xdr.readyState == FakeXDomainRequest.DONE) {
+ throw new Error("Request done");
+ }
+ }
+
+ function verifyResponseBodyType(body) {
+ if (typeof body != "string") {
+ var error = new Error("Attempted to respond to fake XDomainRequest with " +
+ body + ", which is not a string.");
+ error.name = "InvalidBodyException";
+ throw error;
+ }
+ }
+
+ sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, {
+ open: function open(method, url) {
+ this.method = method;
+ this.url = url;
+
+ this.responseText = null;
+ this.sendFlag = false;
+
+ this.readyStateChange(FakeXDomainRequest.OPENED);
+ },
+
+ readyStateChange: function readyStateChange(state) {
+ this.readyState = state;
+ var eventName = "";
+ switch (this.readyState) {
+ case FakeXDomainRequest.UNSENT:
+ break;
+ case FakeXDomainRequest.OPENED:
+ break;
+ case FakeXDomainRequest.LOADING:
+ if (this.sendFlag) {
+ //raise the progress event
+ eventName = "onprogress";
+ }
+ break;
+ case FakeXDomainRequest.DONE:
+ if (this.isTimeout) {
+ eventName = "ontimeout"
+ } else if (this.errorFlag || (this.status < 200 || this.status > 299)) {
+ eventName = "onerror";
+ } else {
+ eventName = "onload"
+ }
+ break;
+ }
+
+ // raising event (if defined)
+ if (eventName) {
+ if (typeof this[eventName] == "function") {
+ try {
+ this[eventName]();
+ } catch (e) {
+ sinon.logError("Fake XHR " + eventName + " handler", e);
+ }
+ }
+ }
+ },
+
+ send: function send(data) {
+ verifyState(this);
+
+ if (!/^(get|head)$/i.test(this.method)) {
+ this.requestBody = data;
+ }
+ this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
+
+ this.errorFlag = false;
+ this.sendFlag = true;
+ this.readyStateChange(FakeXDomainRequest.OPENED);
+
+ if (typeof this.onSend == "function") {
+ this.onSend(this);
+ }
+ },
+
+ abort: function abort() {
+ this.aborted = true;
+ this.responseText = null;
+ this.errorFlag = true;
+
+ if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) {
+ this.readyStateChange(sinon.FakeXDomainRequest.DONE);
+ this.sendFlag = false;
+ }
+ },
+
+ setResponseBody: function setResponseBody(body) {
+ verifyRequestSent(this);
+ verifyResponseBodyType(body);
+
+ var chunkSize = this.chunkSize || 10;
+ var index = 0;
+ this.responseText = "";
+
+ do {
+ this.readyStateChange(FakeXDomainRequest.LOADING);
+ this.responseText += body.substring(index, index + chunkSize);
+ index += chunkSize;
+ } while (index < body.length);
+
+ this.readyStateChange(FakeXDomainRequest.DONE);
+ },
+
+ respond: function respond(status, contentType, body) {
+ // content-type ignored, since XDomainRequest does not carry this
+ // we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease
+ // test integration across browsers
+ this.status = typeof status == "number" ? status : 200;
+ this.setResponseBody(body || "");
+ },
+
+ simulatetimeout: function simulatetimeout() {
+ this.status = 0;
+ this.isTimeout = true;
+ // Access to this should actually throw an error
+ this.responseText = undefined;
+ this.readyStateChange(FakeXDomainRequest.DONE);
+ }
+ });
+
+ sinon.extend(FakeXDomainRequest, {
+ UNSENT: 0,
+ OPENED: 1,
+ LOADING: 3,
+ DONE: 4
+ });
+
+ sinon.useFakeXDomainRequest = function useFakeXDomainRequest() {
+ sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) {
+ if (xdr.supportsXDR) {
+ global.XDomainRequest = xdr.GlobalXDomainRequest;
+ }
+
+ delete sinon.FakeXDomainRequest.restore;
+
+ if (keepOnCreate !== true) {
+ delete sinon.FakeXDomainRequest.onCreate;
+ }
+ };
+ if (xdr.supportsXDR) {
+ global.XDomainRequest = sinon.FakeXDomainRequest;
+ }
+ return sinon.FakeXDomainRequest;
+ };
+
+ sinon.FakeXDomainRequest = FakeXDomainRequest;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./core");
+ require("../extend");
+ require("./event");
+ require("../log_error");
+ makeApi(sinon);
+ module.exports = sinon;
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else {
+ makeApi(sinon);
+ }
+})(typeof global !== "undefined" ? global : self);
+
+/**
+ * @depend core.js
+ * @depend ../extend.js
+ * @depend event.js
+ * @depend ../log_error.js
+ */
+/**
+ * Fake XMLHttpRequest object
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (global) {
+
+ var supportsProgress = typeof ProgressEvent !== "undefined";
+ var supportsCustomEvent = typeof CustomEvent !== "undefined";
+ var supportsFormData = typeof FormData !== "undefined";
+ var sinonXhr = { XMLHttpRequest: global.XMLHttpRequest };
+ sinonXhr.GlobalXMLHttpRequest = global.XMLHttpRequest;
+ sinonXhr.GlobalActiveXObject = global.ActiveXObject;
+ sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject != "undefined";
+ sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest != "undefined";
+ sinonXhr.workingXHR = sinonXhr.supportsXHR ? sinonXhr.GlobalXMLHttpRequest : sinonXhr.supportsActiveX
+ ? function () {
+ return new sinonXhr.GlobalActiveXObject("MSXML2.XMLHTTP.3.0")
+ } : false;
+ sinonXhr.supportsCORS = sinonXhr.supportsXHR && "withCredentials" in (new sinonXhr.GlobalXMLHttpRequest());
+
+ /*jsl:ignore*/
+ var unsafeHeaders = {
+ "Accept-Charset": true,
+ "Accept-Encoding": true,
+ Connection: true,
+ "Content-Length": true,
+ Cookie: true,
+ Cookie2: true,
+ "Content-Transfer-Encoding": true,
+ Date: true,
+ Expect: true,
+ Host: true,
+ "Keep-Alive": true,
+ Referer: true,
+ TE: true,
+ Trailer: true,
+ "Transfer-Encoding": true,
+ Upgrade: true,
+ "User-Agent": true,
+ Via: true
+ };
+ /*jsl:end*/
+
+ // Note that for FakeXMLHttpRequest to work pre ES5
+ // we lose some of the alignment with the spec.
+ // To ensure as close a match as possible,
+ // set responseType before calling open, send or respond;
+ function FakeXMLHttpRequest() {
+ this.readyState = FakeXMLHttpRequest.UNSENT;
+ this.requestHeaders = {};
+ this.requestBody = null;
+ this.status = 0;
+ this.statusText = "";
+ this.upload = new UploadProgress();
+ this.responseType = "";
+ this.response = "";
+ if (sinonXhr.supportsCORS) {
+ this.withCredentials = false;
+ }
+
+ var xhr = this;
+ var events = ["loadstart", "load", "abort", "loadend"];
+
+ function addEventListener(eventName) {
+ xhr.addEventListener(eventName, function (event) {
+ var listener = xhr["on" + eventName];
+
+ if (listener && typeof listener == "function") {
+ listener.call(this, event);
+ }
+ });
+ }
+
+ for (var i = events.length - 1; i >= 0; i--) {
+ addEventListener(events[i]);
+ }
+
+ if (typeof FakeXMLHttpRequest.onCreate == "function") {
+ FakeXMLHttpRequest.onCreate(this);
+ }
+ }
+
+ // An upload object is created for each
+ // FakeXMLHttpRequest and allows upload
+ // events to be simulated using uploadProgress
+ // and uploadError.
+ function UploadProgress() {
+ this.eventListeners = {
+ progress: [],
+ load: [],
+ abort: [],
+ error: []
+ }
+ }
+
+ UploadProgress.prototype.addEventListener = function addEventListener(event, listener) {
+ this.eventListeners[event].push(listener);
+ };
+
+ UploadProgress.prototype.removeEventListener = function removeEventListener(event, listener) {
+ var listeners = this.eventListeners[event] || [];
+
+ for (var i = 0, l = listeners.length; i < l; ++i) {
+ if (listeners[i] == listener) {
+ return listeners.splice(i, 1);
+ }
+ }
+ };
+
+ UploadProgress.prototype.dispatchEvent = function dispatchEvent(event) {
+ var listeners = this.eventListeners[event.type] || [];
+
+ for (var i = 0, listener; (listener = listeners[i]) != null; i++) {
+ listener(event);
+ }
+ };
+
+ function verifyState(xhr) {
+ if (xhr.readyState !== FakeXMLHttpRequest.OPENED) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+
+ if (xhr.sendFlag) {
+ throw new Error("INVALID_STATE_ERR");
+ }
+ }
+
+ function getHeader(headers, header) {
+ header = header.toLowerCase();
+
+ for (var h in headers) {
+ if (h.toLowerCase() == header) {
+ return h;
+ }
+ }
+
+ return null;
+ }
+
+ // filtering to enable a white-list version of Sinon FakeXhr,
+ // where whitelisted requests are passed through to real XHR
+ function each(collection, callback) {
+ if (!collection) {
+ return;
+ }
+
+ for (var i = 0, l = collection.length; i < l; i += 1) {
+ callback(collection[i]);
+ }
+ }
+ function some(collection, callback) {
+ for (var index = 0; index < collection.length; index++) {
+ if (callback(collection[index]) === true) {
+ return true;
+ }
+ }
+ return false;
+ }
+ // largest arity in XHR is 5 - XHR#open
+ var apply = function (obj, method, args) {
+ switch (args.length) {
+ case 0: return obj[method]();
+ case 1: return obj[method](args[0]);
+ case 2: return obj[method](args[0], args[1]);
+ case 3: return obj[method](args[0], args[1], args[2]);
+ case 4: return obj[method](args[0], args[1], args[2], args[3]);
+ case 5: return obj[method](args[0], args[1], args[2], args[3], args[4]);
+ }
+ };
+
+ FakeXMLHttpRequest.filters = [];
+ FakeXMLHttpRequest.addFilter = function addFilter(fn) {
+ this.filters.push(fn)
+ };
+ var IE6Re = /MSIE 6/;
+ FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) {
+ var xhr = new sinonXhr.workingXHR();
+ each([
+ "open",
+ "setRequestHeader",
+ "send",
+ "abort",
+ "getResponseHeader",
+ "getAllResponseHeaders",
+ "addEventListener",
+ "overrideMimeType",
+ "removeEventListener"
+ ], function (method) {
+ fakeXhr[method] = function () {
+ return apply(xhr, method, arguments);
+ };
+ });
+
+ var copyAttrs = function (args) {
+ each(args, function (attr) {
+ try {
+ fakeXhr[attr] = xhr[attr]
+ } catch (e) {
+ if (!IE6Re.test(navigator.userAgent)) {
+ throw e;
+ }
+ }
+ });
+ };
+
+ var stateChange = function stateChange() {
+ fakeXhr.readyState = xhr.readyState;
+ if (xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ copyAttrs(["status", "statusText"]);
+ }
+ if (xhr.readyState >= FakeXMLHttpRequest.LOADING) {
+ copyAttrs(["responseText", "response"]);
+ }
+ if (xhr.readyState === FakeXMLHttpRequest.DONE) {
+ copyAttrs(["responseXML"]);
+ }
+ if (fakeXhr.onreadystatechange) {
+ fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr });
+ }
+ };
+
+ if (xhr.addEventListener) {
+ for (var event in fakeXhr.eventListeners) {
+ if (fakeXhr.eventListeners.hasOwnProperty(event)) {
+ each(fakeXhr.eventListeners[event], function (handler) {
+ xhr.addEventListener(event, handler);
+ });
+ }
+ }
+ xhr.addEventListener("readystatechange", stateChange);
+ } else {
+ xhr.onreadystatechange = stateChange;
+ }
+ apply(xhr, "open", xhrArgs);
+ };
+ FakeXMLHttpRequest.useFilters = false;
+
+ function verifyRequestOpened(xhr) {
+ if (xhr.readyState != FakeXMLHttpRequest.OPENED) {
+ throw new Error("INVALID_STATE_ERR - " + xhr.readyState);
+ }
+ }
+
+ function verifyRequestSent(xhr) {
+ if (xhr.readyState == FakeXMLHttpRequest.DONE) {
+ throw new Error("Request done");
+ }
+ }
+
+ function verifyHeadersReceived(xhr) {
+ if (xhr.async && xhr.readyState != FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ throw new Error("No headers received");
+ }
+ }
+
+ function verifyResponseBodyType(body) {
+ if (typeof body != "string") {
+ var error = new Error("Attempted to respond to fake XMLHttpRequest with " +
+ body + ", which is not a string.");
+ error.name = "InvalidBodyException";
+ throw error;
+ }
+ }
+
+ FakeXMLHttpRequest.parseXML = function parseXML(text) {
+ var xmlDoc;
+
+ if (typeof DOMParser != "undefined") {
+ var parser = new DOMParser();
+ xmlDoc = parser.parseFromString(text, "text/xml");
+ } else {
+ xmlDoc = new ActiveXObject("Microsoft.XMLDOM");
+ xmlDoc.async = "false";
+ xmlDoc.loadXML(text);
+ }
+
+ return xmlDoc;
+ };
+
+ FakeXMLHttpRequest.statusCodes = {
+ 100: "Continue",
+ 101: "Switching Protocols",
+ 200: "OK",
+ 201: "Created",
+ 202: "Accepted",
+ 203: "Non-Authoritative Information",
+ 204: "No Content",
+ 205: "Reset Content",
+ 206: "Partial Content",
+ 207: "Multi-Status",
+ 300: "Multiple Choice",
+ 301: "Moved Permanently",
+ 302: "Found",
+ 303: "See Other",
+ 304: "Not Modified",
+ 305: "Use Proxy",
+ 307: "Temporary Redirect",
+ 400: "Bad Request",
+ 401: "Unauthorized",
+ 402: "Payment Required",
+ 403: "Forbidden",
+ 404: "Not Found",
+ 405: "Method Not Allowed",
+ 406: "Not Acceptable",
+ 407: "Proxy Authentication Required",
+ 408: "Request Timeout",
+ 409: "Conflict",
+ 410: "Gone",
+ 411: "Length Required",
+ 412: "Precondition Failed",
+ 413: "Request Entity Too Large",
+ 414: "Request-URI Too Long",
+ 415: "Unsupported Media Type",
+ 416: "Requested Range Not Satisfiable",
+ 417: "Expectation Failed",
+ 422: "Unprocessable Entity",
+ 500: "Internal Server Error",
+ 501: "Not Implemented",
+ 502: "Bad Gateway",
+ 503: "Service Unavailable",
+ 504: "Gateway Timeout",
+ 505: "HTTP Version Not Supported"
+ };
+
+ function makeApi(sinon) {
+ sinon.xhr = sinonXhr;
+
+ sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, {
+ async: true,
+
+ open: function open(method, url, async, username, password) {
+ this.method = method;
+ this.url = url;
+ this.async = typeof async == "boolean" ? async : true;
+ this.username = username;
+ this.password = password;
+ this.responseText = null;
+ this.response = this.responseType === "json" ? null : "";
+ this.responseXML = null;
+ this.requestHeaders = {};
+ this.sendFlag = false;
+
+ if (FakeXMLHttpRequest.useFilters === true) {
+ var xhrArgs = arguments;
+ var defake = some(FakeXMLHttpRequest.filters, function (filter) {
+ return filter.apply(this, xhrArgs)
+ });
+ if (defake) {
+ return FakeXMLHttpRequest.defake(this, arguments);
+ }
+ }
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
+ },
+
+ readyStateChange: function readyStateChange(state) {
+ this.readyState = state;
+
+ if (typeof this.onreadystatechange == "function") {
+ try {
+ this.onreadystatechange();
+ } catch (e) {
+ sinon.logError("Fake XHR onreadystatechange handler", e);
+ }
+ }
+
+ switch (this.readyState) {
+ case FakeXMLHttpRequest.DONE:
+ if (supportsProgress) {
+ this.upload.dispatchEvent(new sinon.ProgressEvent("progress", {loaded: 100, total: 100}));
+ this.dispatchEvent(new sinon.ProgressEvent("progress", {loaded: 100, total: 100}));
+ }
+ this.upload.dispatchEvent(new sinon.Event("load", false, false, this));
+ this.dispatchEvent(new sinon.Event("load", false, false, this));
+ this.dispatchEvent(new sinon.Event("loadend", false, false, this));
+ break;
+ }
+
+ this.dispatchEvent(new sinon.Event("readystatechange"));
+ },
+
+ setRequestHeader: function setRequestHeader(header, value) {
+ verifyState(this);
+
+ if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) {
+ throw new Error("Refused to set unsafe header \"" + header + "\"");
+ }
+
+ if (this.requestHeaders[header]) {
+ this.requestHeaders[header] += "," + value;
+ } else {
+ this.requestHeaders[header] = value;
+ }
+ },
+
+ // Helps testing
+ setResponseHeaders: function setResponseHeaders(headers) {
+ verifyRequestOpened(this);
+ this.responseHeaders = {};
+
+ for (var header in headers) {
+ if (headers.hasOwnProperty(header)) {
+ this.responseHeaders[header] = headers[header];
+ }
+ }
+
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED);
+ } else {
+ this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED;
+ }
+ },
+
+ // Currently treats ALL data as a DOMString (i.e. no Document)
+ send: function send(data) {
+ verifyState(this);
+
+ if (!/^(get|head)$/i.test(this.method)) {
+ var contentType = getHeader(this.requestHeaders, "Content-Type");
+ if (this.requestHeaders[contentType]) {
+ var value = this.requestHeaders[contentType].split(";");
+ this.requestHeaders[contentType] = value[0] + ";charset=utf-8";
+ } else if (supportsFormData && !(data instanceof FormData)) {
+ this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8";
+ }
+
+ this.requestBody = data;
+ }
+
+ this.errorFlag = false;
+ this.sendFlag = this.async;
+ this.response = this.responseType === "json" ? null : "";
+ this.readyStateChange(FakeXMLHttpRequest.OPENED);
+
+ if (typeof this.onSend == "function") {
+ this.onSend(this);
+ }
+
+ this.dispatchEvent(new sinon.Event("loadstart", false, false, this));
+ },
+
+ abort: function abort() {
+ this.aborted = true;
+ this.responseText = null;
+ this.response = this.responseType === "json" ? null : "";
+ this.errorFlag = true;
+ this.requestHeaders = {};
+ this.responseHeaders = {};
+
+ if (this.readyState > FakeXMLHttpRequest.UNSENT && this.sendFlag) {
+ this.readyStateChange(FakeXMLHttpRequest.DONE);
+ this.sendFlag = false;
+ }
+
+ this.readyState = FakeXMLHttpRequest.UNSENT;
+
+ this.dispatchEvent(new sinon.Event("abort", false, false, this));
+
+ this.upload.dispatchEvent(new sinon.Event("abort", false, false, this));
+
+ if (typeof this.onerror === "function") {
+ this.onerror();
+ }
+ },
+
+ getResponseHeader: function getResponseHeader(header) {
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ return null;
+ }
+
+ if (/^Set-Cookie2?$/i.test(header)) {
+ return null;
+ }
+
+ header = getHeader(this.responseHeaders, header);
+
+ return this.responseHeaders[header] || null;
+ },
+
+ getAllResponseHeaders: function getAllResponseHeaders() {
+ if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) {
+ return "";
+ }
+
+ var headers = "";
+
+ for (var header in this.responseHeaders) {
+ if (this.responseHeaders.hasOwnProperty(header) &&
+ !/^Set-Cookie2?$/i.test(header)) {
+ headers += header + ": " + this.responseHeaders[header] + "\r\n";
+ }
+ }
+
+ return headers;
+ },
+
+ setResponseBody: function setResponseBody(body) {
+ verifyRequestSent(this);
+ verifyHeadersReceived(this);
+ verifyResponseBodyType(body);
+
+ var chunkSize = this.chunkSize || 10;
+ var index = 0;
+ this.responseText = "";
+
+ do {
+ if (this.async) {
+ this.readyStateChange(FakeXMLHttpRequest.LOADING);
+ }
+
+ this.responseText += body.substring(index, index + chunkSize);
+ index += chunkSize;
+ } while (index < body.length);
+
+ var type = this.getResponseHeader("Content-Type");
+
+ if (this.responseText &&
+ (!type || /(text\/xml)|(application\/xml)|(\+xml)/.test(type))) {
+ try {
+ this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText);
+ } catch (e) {
+ // Unable to parse XML - no biggie
+ }
+ }
+
+ this.response = this.responseType === "json" ? JSON.parse(this.responseText) : this.responseText;
+ this.readyStateChange(FakeXMLHttpRequest.DONE);
+ },
+
+ respond: function respond(status, headers, body) {
+ this.status = typeof status == "number" ? status : 200;
+ this.statusText = FakeXMLHttpRequest.statusCodes[this.status];
+ this.setResponseHeaders(headers || {});
+ this.setResponseBody(body || "");
+ },
+
+ uploadProgress: function uploadProgress(progressEventRaw) {
+ if (supportsProgress) {
+ this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
+ }
+ },
+
+ downloadProgress: function downloadProgress(progressEventRaw) {
+ if (supportsProgress) {
+ this.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw));
+ }
+ },
+
+ uploadError: function uploadError(error) {
+ if (supportsCustomEvent) {
+ this.upload.dispatchEvent(new sinon.CustomEvent("error", {detail: error}));
+ }
+ }
+ });
+
+ sinon.extend(FakeXMLHttpRequest, {
+ UNSENT: 0,
+ OPENED: 1,
+ HEADERS_RECEIVED: 2,
+ LOADING: 3,
+ DONE: 4
+ });
+
+ sinon.useFakeXMLHttpRequest = function () {
+ FakeXMLHttpRequest.restore = function restore(keepOnCreate) {
+ if (sinonXhr.supportsXHR) {
+ global.XMLHttpRequest = sinonXhr.GlobalXMLHttpRequest;
+ }
+
+ if (sinonXhr.supportsActiveX) {
+ global.ActiveXObject = sinonXhr.GlobalActiveXObject;
+ }
+
+ delete FakeXMLHttpRequest.restore;
+
+ if (keepOnCreate !== true) {
+ delete FakeXMLHttpRequest.onCreate;
+ }
+ };
+ if (sinonXhr.supportsXHR) {
+ global.XMLHttpRequest = FakeXMLHttpRequest;
+ }
+
+ if (sinonXhr.supportsActiveX) {
+ global.ActiveXObject = function ActiveXObject(objId) {
+ if (objId == "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) {
+
+ return new FakeXMLHttpRequest();
+ }
+
+ return new sinonXhr.GlobalActiveXObject(objId);
+ };
+ }
+
+ return FakeXMLHttpRequest;
+ };
+
+ sinon.FakeXMLHttpRequest = FakeXMLHttpRequest;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./core");
+ require("../extend");
+ require("./event");
+ require("../log_error");
+ makeApi(sinon);
+ module.exports = sinon;
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (typeof sinon === "undefined") {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+
+})(typeof global !== "undefined" ? global : self);
+
+/**
+ * @depend fake_xdomain_request.js
+ * @depend fake_xml_http_request.js
+ * @depend ../format.js
+ * @depend ../log_error.js
+ */
+/**
+ * The Sinon "server" mimics a web server that receives requests from
+ * sinon.FakeXMLHttpRequest and provides an API to respond to those requests,
+ * both synchronously and asynchronously. To respond synchronuously, canned
+ * answers have to be provided upfront.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+if (typeof sinon == "undefined") {
+ var sinon = {};
+}
+
+(function () {
+ var push = [].push;
+ function F() {}
+
+ function create(proto) {
+ F.prototype = proto;
+ return new F();
+ }
+
+ function responseArray(handler) {
+ var response = handler;
+
+ if (Object.prototype.toString.call(handler) != "[object Array]") {
+ response = [200, {}, handler];
+ }
+
+ if (typeof response[2] != "string") {
+ throw new TypeError("Fake server response body should be string, but was " +
+ typeof response[2]);
+ }
+
+ return response;
+ }
+
+ var wloc = typeof window !== "undefined" ? window.location : {};
+ var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host);
+
+ function matchOne(response, reqMethod, reqUrl) {
+ var rmeth = response.method;
+ var matchMethod = !rmeth || rmeth.toLowerCase() == reqMethod.toLowerCase();
+ var url = response.url;
+ var matchUrl = !url || url == reqUrl || (typeof url.test == "function" && url.test(reqUrl));
+
+ return matchMethod && matchUrl;
+ }
+
+ function match(response, request) {
+ var requestUrl = request.url;
+
+ if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) {
+ requestUrl = requestUrl.replace(rCurrLoc, "");
+ }
+
+ if (matchOne(response, this.getHTTPMethod(request), requestUrl)) {
+ if (typeof response.response == "function") {
+ var ru = response.url;
+ var args = [request].concat(ru && typeof ru.exec == "function" ? ru.exec(requestUrl).slice(1) : []);
+ return response.response.apply(response, args);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ function makeApi(sinon) {
+ sinon.fakeServer = {
+ create: function () {
+ var server = create(this);
+ if (!sinon.xhr.supportsCORS) {
+ this.xhr = sinon.useFakeXDomainRequest();
+ } else {
+ this.xhr = sinon.useFakeXMLHttpRequest();
+ }
+ server.requests = [];
+
+ this.xhr.onCreate = function (xhrObj) {
+ server.addRequest(xhrObj);
+ };
+
+ return server;
+ },
+
+ addRequest: function addRequest(xhrObj) {
+ var server = this;
+ push.call(this.requests, xhrObj);
+
+ xhrObj.onSend = function () {
+ server.handleRequest(this);
+
+ if (server.respondImmediately) {
+ server.respond();
+ } else if (server.autoRespond && !server.responding) {
+ setTimeout(function () {
+ server.responding = false;
+ server.respond();
+ }, server.autoRespondAfter || 10);
+
+ server.responding = true;
+ }
+ };
+ },
+
+ getHTTPMethod: function getHTTPMethod(request) {
+ if (this.fakeHTTPMethods && /post/i.test(request.method)) {
+ var matches = (request.requestBody || "").match(/_method=([^\b;]+)/);
+ return !!matches ? matches[1] : request.method;
+ }
+
+ return request.method;
+ },
+
+ handleRequest: function handleRequest(xhr) {
+ if (xhr.async) {
+ if (!this.queue) {
+ this.queue = [];
+ }
+
+ push.call(this.queue, xhr);
+ } else {
+ this.processRequest(xhr);
+ }
+ },
+
+ log: function log(response, request) {
+ var str;
+
+ str = "Request:\n" + sinon.format(request) + "\n\n";
+ str += "Response:\n" + sinon.format(response) + "\n\n";
+
+ sinon.log(str);
+ },
+
+ respondWith: function respondWith(method, url, body) {
+ if (arguments.length == 1 && typeof method != "function") {
+ this.response = responseArray(method);
+ return;
+ }
+
+ if (!this.responses) {
+ this.responses = [];
+ }
+
+ if (arguments.length == 1) {
+ body = method;
+ url = method = null;
+ }
+
+ if (arguments.length == 2) {
+ body = url;
+ url = method;
+ method = null;
+ }
+
+ push.call(this.responses, {
+ method: method,
+ url: url,
+ response: typeof body == "function" ? body : responseArray(body)
+ });
+ },
+
+ respond: function respond() {
+ if (arguments.length > 0) {
+ this.respondWith.apply(this, arguments);
+ }
+
+ var queue = this.queue || [];
+ var requests = queue.splice(0, queue.length);
+ var request;
+
+ while (request = requests.shift()) {
+ this.processRequest(request);
+ }
+ },
+
+ processRequest: function processRequest(request) {
+ try {
+ if (request.aborted) {
+ return;
+ }
+
+ var response = this.response || [404, {}, ""];
+
+ if (this.responses) {
+ for (var l = this.responses.length, i = l - 1; i >= 0; i--) {
+ if (match.call(this, this.responses[i], request)) {
+ response = this.responses[i].response;
+ break;
+ }
+ }
+ }
+
+ if (request.readyState != 4) {
+ this.log(response, request);
+
+ request.respond(response[0], response[1], response[2]);
+ }
+ } catch (e) {
+ sinon.logError("Fake server request processing", e);
+ }
+ },
+
+ restore: function restore() {
+ return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments);
+ }
+ };
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./core");
+ require("./fake_xdomain_request");
+ require("./fake_xml_http_request");
+ require("../format");
+ makeApi(sinon);
+ module.exports = sinon;
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else {
+ makeApi(sinon);
+ }
+}());
+
+/**
+ * @depend fake_server.js
+ * @depend fake_timers.js
+ */
+/**
+ * Add-on for sinon.fakeServer that automatically handles a fake timer along with
+ * the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery
+ * 1.3.x, which does not use xhr object's onreadystatehandler at all - instead,
+ * it polls the object for completion with setInterval. Dispite the direct
+ * motivation, there is nothing jQuery-specific in this file, so it can be used
+ * in any environment where the ajax implementation depends on setInterval or
+ * setTimeout.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function () {
+ function makeApi(sinon) {
+ function Server() {}
+ Server.prototype = sinon.fakeServer;
+
+ sinon.fakeServerWithClock = new Server();
+
+ sinon.fakeServerWithClock.addRequest = function addRequest(xhr) {
+ if (xhr.async) {
+ if (typeof setTimeout.clock == "object") {
+ this.clock = setTimeout.clock;
+ } else {
+ this.clock = sinon.useFakeTimers();
+ this.resetClock = true;
+ }
+
+ if (!this.longestTimeout) {
+ var clockSetTimeout = this.clock.setTimeout;
+ var clockSetInterval = this.clock.setInterval;
+ var server = this;
+
+ this.clock.setTimeout = function (fn, timeout) {
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+ return clockSetTimeout.apply(this, arguments);
+ };
+
+ this.clock.setInterval = function (fn, timeout) {
+ server.longestTimeout = Math.max(timeout, server.longestTimeout || 0);
+
+ return clockSetInterval.apply(this, arguments);
+ };
+ }
+ }
+
+ return sinon.fakeServer.addRequest.call(this, xhr);
+ };
+
+ sinon.fakeServerWithClock.respond = function respond() {
+ var returnVal = sinon.fakeServer.respond.apply(this, arguments);
+
+ if (this.clock) {
+ this.clock.tick(this.longestTimeout || 0);
+ this.longestTimeout = 0;
+
+ if (this.resetClock) {
+ this.clock.restore();
+ this.resetClock = false;
+ }
+ }
+
+ return returnVal;
+ };
+
+ sinon.fakeServerWithClock.restore = function restore() {
+ if (this.clock) {
+ this.clock.restore();
+ }
+
+ return sinon.fakeServer.restore.apply(this, arguments);
+ };
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require) {
+ var sinon = require("./core");
+ require("./fake_server");
+ require("./fake_timers");
+ makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require);
+ } else {
+ makeApi(sinon);
+ }
+}());
+
+/**
+ * @depend util/core.js
+ * @depend extend.js
+ * @depend collection.js
+ * @depend util/fake_timers.js
+ * @depend util/fake_server_with_clock.js
+ */
+/**
+ * Manages fake collections as well as fake utilities such as Sinon's
+ * timers and fake XHR implementation in one convenient object.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function () {
+ function makeApi(sinon) {
+ var push = [].push;
+
+ function exposeValue(sandbox, config, key, value) {
+ if (!value) {
+ return;
+ }
+
+ if (config.injectInto && !(key in config.injectInto)) {
+ config.injectInto[key] = value;
+ sandbox.injectedKeys.push(key);
+ } else {
+ push.call(sandbox.args, value);
+ }
+ }
+
+ function prepareSandboxFromConfig(config) {
+ var sandbox = sinon.create(sinon.sandbox);
+
+ if (config.useFakeServer) {
+ if (typeof config.useFakeServer == "object") {
+ sandbox.serverPrototype = config.useFakeServer;
+ }
+
+ sandbox.useFakeServer();
+ }
+
+ if (config.useFakeTimers) {
+ if (typeof config.useFakeTimers == "object") {
+ sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers);
+ } else {
+ sandbox.useFakeTimers();
+ }
+ }
+
+ return sandbox;
+ }
+
+ sinon.sandbox = sinon.extend(sinon.create(sinon.collection), {
+ useFakeTimers: function useFakeTimers() {
+ this.clock = sinon.useFakeTimers.apply(sinon, arguments);
+
+ return this.add(this.clock);
+ },
+
+ serverPrototype: sinon.fakeServer,
+
+ useFakeServer: function useFakeServer() {
+ var proto = this.serverPrototype || sinon.fakeServer;
+
+ if (!proto || !proto.create) {
+ return null;
+ }
+
+ this.server = proto.create();
+ return this.add(this.server);
+ },
+
+ inject: function (obj) {
+ sinon.collection.inject.call(this, obj);
+
+ if (this.clock) {
+ obj.clock = this.clock;
+ }
+
+ if (this.server) {
+ obj.server = this.server;
+ obj.requests = this.server.requests;
+ }
+
+ obj.match = sinon.match;
+
+ return obj;
+ },
+
+ restore: function () {
+ sinon.collection.restore.apply(this, arguments);
+ this.restoreContext();
+ },
+
+ restoreContext: function () {
+ if (this.injectedKeys) {
+ for (var i = 0, j = this.injectedKeys.length; i < j; i++) {
+ delete this.injectInto[this.injectedKeys[i]];
+ }
+ this.injectedKeys = [];
+ }
+ },
+
+ create: function (config) {
+ if (!config) {
+ return sinon.create(sinon.sandbox);
+ }
+
+ var sandbox = prepareSandboxFromConfig(config);
+ sandbox.args = sandbox.args || [];
+ sandbox.injectedKeys = [];
+ sandbox.injectInto = config.injectInto;
+ var prop, value, exposed = sandbox.inject({});
+
+ if (config.properties) {
+ for (var i = 0, l = config.properties.length; i < l; i++) {
+ prop = config.properties[i];
+ value = exposed[prop] || prop == "sandbox" && sandbox;
+ exposeValue(sandbox, config, prop, value);
+ }
+ } else {
+ exposeValue(sandbox, config, "sandbox", value);
+ }
+
+ return sandbox;
+ },
+
+ match: sinon.match
+ });
+
+ sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer;
+
+ return sinon.sandbox;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./extend");
+ require("./util/fake_server_with_clock");
+ require("./util/fake_timers");
+ require("./collection");
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}());
+
+/**
+ * @depend util/core.js
+ * @depend sandbox.js
+ */
+/**
+ * Test function, sandboxes fakes
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ function makeApi(sinon) {
+ var slice = Array.prototype.slice;
+
+ function test(callback) {
+ var type = typeof callback;
+
+ if (type != "function") {
+ throw new TypeError("sinon.test needs to wrap a test function, got " + type);
+ }
+
+ function sinonSandboxedTest() {
+ var config = sinon.getConfig(sinon.config);
+ config.injectInto = config.injectIntoThis && this || config.injectInto;
+ var sandbox = sinon.sandbox.create(config);
+ var args = slice.call(arguments);
+ var oldDone = args.length && args[args.length - 1];
+ var exception, result;
+
+ if (typeof oldDone == "function") {
+ args[args.length - 1] = function sinonDone(result) {
+ if (result) {
+ sandbox.restore();
+ throw exception;
+ } else {
+ sandbox.verifyAndRestore();
+ }
+ oldDone(result);
+ };
+ }
+
+ try {
+ result = callback.apply(this, args.concat(sandbox.args));
+ } catch (e) {
+ exception = e;
+ }
+
+ if (typeof oldDone != "function") {
+ if (typeof exception !== "undefined") {
+ sandbox.restore();
+ throw exception;
+ } else {
+ sandbox.verifyAndRestore();
+ }
+ }
+
+ return result;
+ }
+
+ if (callback.length) {
+ return function sinonAsyncSandboxedTest(callback) {
+ return sinonSandboxedTest.apply(this, arguments);
+ };
+ }
+
+ return sinonSandboxedTest;
+ }
+
+ test.config = {
+ injectIntoThis: true,
+ injectInto: null,
+ properties: ["spy", "stub", "mock", "clock", "server", "requests"],
+ useFakeTimers: true,
+ useFakeServer: true
+ };
+
+ sinon.test = test;
+ return test;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./sandbox");
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (sinon) {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend util/core.js
+ * @depend test.js
+ */
+/**
+ * Test case, sandboxes all test functions
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon) {
+ function createTest(property, setUp, tearDown) {
+ return function () {
+ if (setUp) {
+ setUp.apply(this, arguments);
+ }
+
+ var exception, result;
+
+ try {
+ result = property.apply(this, arguments);
+ } catch (e) {
+ exception = e;
+ }
+
+ if (tearDown) {
+ tearDown.apply(this, arguments);
+ }
+
+ if (exception) {
+ throw exception;
+ }
+
+ return result;
+ };
+ }
+
+ function makeApi(sinon) {
+ function testCase(tests, prefix) {
+ if (!tests || typeof tests != "object") {
+ throw new TypeError("sinon.testCase needs an object with test functions");
+ }
+
+ prefix = prefix || "test";
+ var rPrefix = new RegExp("^" + prefix);
+ var methods = {}, testName, property, method;
+ var setUp = tests.setUp;
+ var tearDown = tests.tearDown;
+
+ for (testName in tests) {
+ if (tests.hasOwnProperty(testName) && !/^(setUp|tearDown)$/.test(testName)) {
+ property = tests[testName];
+
+ if (typeof property == "function" && rPrefix.test(testName)) {
+ method = property;
+
+ if (setUp || tearDown) {
+ method = createTest(property, setUp, tearDown);
+ }
+
+ methods[testName] = sinon.test(method);
+ } else {
+ methods[testName] = tests[testName];
+ }
+ }
+ }
+
+ return methods;
+ }
+
+ sinon.testCase = testCase;
+ return testCase;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./test");
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+}(typeof sinon == "object" && sinon || null));
+
+/**
+ * @depend times_in_words.js
+ * @depend util/core.js
+ * @depend match.js
+ * @depend format.js
+ */
+/**
+ * Assertions matching the test spy retrieval interface.
+ *
+ * @author Christian Johansen (christian@cjohansen.no)
+ * @license BSD
+ *
+ * Copyright (c) 2010-2013 Christian Johansen
+ */
+
+(function (sinon, global) {
+ var slice = Array.prototype.slice;
+
+ function makeApi(sinon) {
+ var assert;
+
+ function verifyIsStub() {
+ var method;
+
+ for (var i = 0, l = arguments.length; i < l; ++i) {
+ method = arguments[i];
+
+ if (!method) {
+ assert.fail("fake is not a spy");
+ }
+
+ if (method.proxy && method.proxy.isSinonProxy) {
+ verifyIsStub(method.proxy);
+ } else {
+ if (typeof method != "function") {
+ assert.fail(method + " is not a function");
+ }
+
+ if (typeof method.getCall != "function") {
+ assert.fail(method + " is not stubbed");
+ }
+ }
+
+ }
+ }
+
+ function failAssertion(object, msg) {
+ object = object || global;
+ var failMethod = object.fail || assert.fail;
+ failMethod.call(object, msg);
+ }
+
+ function mirrorPropAsAssertion(name, method, message) {
+ if (arguments.length == 2) {
+ message = method;
+ method = name;
+ }
+
+ assert[name] = function (fake) {
+ verifyIsStub(fake);
+
+ var args = slice.call(arguments, 1);
+ var failed = false;
+
+ if (typeof method == "function") {
+ failed = !method(fake);
+ } else {
+ failed = typeof fake[method] == "function" ?
+ !fake[method].apply(fake, args) : !fake[method];
+ }
+
+ if (failed) {
+ failAssertion(this, (fake.printf || fake.proxy.printf).apply(fake, [message].concat(args)));
+ } else {
+ assert.pass(name);
+ }
+ };
+ }
+
+ function exposedName(prefix, prop) {
+ return !prefix || /^fail/.test(prop) ? prop :
+ prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1);
+ }
+
+ assert = {
+ failException: "AssertError",
+
+ fail: function fail(message) {
+ var error = new Error(message);
+ error.name = this.failException || assert.failException;
+
+ throw error;
+ },
+
+ pass: function pass(assertion) {},
+
+ callOrder: function assertCallOrder() {
+ verifyIsStub.apply(null, arguments);
+ var expected = "", actual = "";
+
+ if (!sinon.calledInOrder(arguments)) {
+ try {
+ expected = [].join.call(arguments, ", ");
+ var calls = slice.call(arguments);
+ var i = calls.length;
+ while (i) {
+ if (!calls[--i].called) {
+ calls.splice(i, 1);
+ }
+ }
+ actual = sinon.orderByFirstCall(calls).join(", ");
+ } catch (e) {
+ // If this fails, we'll just fall back to the blank string
+ }
+
+ failAssertion(this, "expected " + expected + " to be " +
+ "called in order but were called as " + actual);
+ } else {
+ assert.pass("callOrder");
+ }
+ },
+
+ callCount: function assertCallCount(method, count) {
+ verifyIsStub(method);
+
+ if (method.callCount != count) {
+ var msg = "expected %n to be called " + sinon.timesInWords(count) +
+ " but was called %c%C";
+ failAssertion(this, method.printf(msg));
+ } else {
+ assert.pass("callCount");
+ }
+ },
+
+ expose: function expose(target, options) {
+ if (!target) {
+ throw new TypeError("target is null or undefined");
+ }
+
+ var o = options || {};
+ var prefix = typeof o.prefix == "undefined" && "assert" || o.prefix;
+ var includeFail = typeof o.includeFail == "undefined" || !!o.includeFail;
+
+ for (var method in this) {
+ if (method != "expose" && (includeFail || !/^(fail)/.test(method))) {
+ target[exposedName(prefix, method)] = this[method];
+ }
+ }
+
+ return target;
+ },
+
+ match: function match(actual, expectation) {
+ var matcher = sinon.match(expectation);
+ if (matcher.test(actual)) {
+ assert.pass("match");
+ } else {
+ var formatted = [
+ "expected value to match",
+ " expected = " + sinon.format(expectation),
+ " actual = " + sinon.format(actual)
+ ]
+ failAssertion(this, formatted.join("\n"));
+ }
+ }
+ };
+
+ mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called");
+ mirrorPropAsAssertion("notCalled", function (spy) {
+ return !spy.called;
+ }, "expected %n to not have been called but was called %c%C");
+ mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C");
+ mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C");
+ mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C");
+ mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t");
+ mirrorPropAsAssertion("alwaysCalledOn", "expected %n to always be called with %1 as this but was called with %t");
+ mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new");
+ mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new");
+ mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C");
+ mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C");
+ mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C");
+ mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C");
+ mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C");
+ mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C");
+ mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C");
+ mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C");
+ mirrorPropAsAssertion("threw", "%n did not throw exception%C");
+ mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C");
+
+ sinon.assert = assert;
+ return assert;
+ }
+
+ var isNode = typeof module !== "undefined" && module.exports && typeof require == "function";
+ var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd;
+
+ function loadDependencies(require, exports, module) {
+ var sinon = require("./util/core");
+ require("./match");
+ require("./format");
+ module.exports = makeApi(sinon);
+ }
+
+ if (isAMD) {
+ define(loadDependencies);
+ } else if (isNode) {
+ loadDependencies(require, module.exports, module);
+ } else if (!sinon) {
+ return;
+ } else {
+ makeApi(sinon);
+ }
+
+}(typeof sinon == "object" && sinon || null, typeof window != "undefined" ? window : (typeof self != "undefined") ? self : global));
+
+ return sinon;
+}));
diff --git a/resources/lib/sinonjs/sinon-ie-1.10.3.js b/resources/lib/sinonjs/sinon-ie-1.15.4.js
index de8c23d1..9eac9580 100644
--- a/resources/lib/sinonjs/sinon-ie-1.10.3.js
+++ b/resources/lib/sinonjs/sinon-ie-1.15.4.js
@@ -1,5 +1,5 @@
/**
- * Sinon.JS 1.10.3, 2014/07/11
+ * Sinon.JS 1.15.4, 2015/06/27
*
* @author Christian Johansen (christian@cjohansen.no)
* @author Contributors: https://github.com/cjohansen/Sinon.JS/blob/master/AUTHORS
@@ -33,7 +33,6 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-/*global sinon, setTimeout, setInterval, clearTimeout, clearInterval, Date*/
/**
* Helps IE run the fake timers. By defining global functions, IE allows
* them to be overwritten at a later point. If these are not defined like
@@ -47,25 +46,26 @@
*
* Copyright (c) 2010-2013 Christian Johansen
*/
-function setTimeout() {}
-function clearTimeout() {}
-function setImmediate() {}
-function clearImmediate() {}
-function setInterval() {}
-function clearInterval() {}
-function Date() {}
+if (typeof window !== "undefined") {
+ function setTimeout() {}
+ function clearTimeout() {}
+ function setImmediate() {}
+ function clearImmediate() {}
+ function setInterval() {}
+ function clearInterval() {}
+ function Date() {}
-// Reassign the original functions. Now their writable attribute
-// should be true. Hackish, I know, but it works.
-setTimeout = sinon.timers.setTimeout;
-clearTimeout = sinon.timers.clearTimeout;
-setImmediate = sinon.timers.setImmediate;
-clearImmediate = sinon.timers.clearImmediate;
-setInterval = sinon.timers.setInterval;
-clearInterval = sinon.timers.clearInterval;
-Date = sinon.timers.Date;
+ // Reassign the original functions. Now their writable attribute
+ // should be true. Hackish, I know, but it works.
+ setTimeout = sinon.timers.setTimeout;
+ clearTimeout = sinon.timers.clearTimeout;
+ setImmediate = sinon.timers.setImmediate;
+ clearImmediate = sinon.timers.clearImmediate;
+ setInterval = sinon.timers.setInterval;
+ clearInterval = sinon.timers.clearInterval;
+ Date = sinon.timers.Date;
+}
-/*global sinon*/
/**
* Helps IE run the fake XMLHttpRequest. By defining global functions, IE allows
* them to be overwritten at a later point. If these are not defined like
@@ -79,12 +79,13 @@ Date = sinon.timers.Date;
*
* Copyright (c) 2010-2013 Christian Johansen
*/
-function XMLHttpRequest() {}
+if (typeof window !== "undefined") {
+ function XMLHttpRequest() {}
-// Reassign the original function. Now its writable attribute
-// should be true. Hackish, I know, but it works.
-XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
-/*global sinon*/
+ // Reassign the original function. Now its writable attribute
+ // should be true. Hackish, I know, but it works.
+ XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
+}
/**
* Helps IE run the fake XDomainRequest. By defining global functions, IE allows
* them to be overwritten at a later point. If these are not defined like
@@ -93,8 +94,10 @@ XMLHttpRequest = sinon.xhr.XMLHttpRequest || undefined;
*
* If you don't require fake XDR to work in IE, don't include this file.
*/
-function XDomainRequest() {}
+if (typeof window !== "undefined") {
+ function XDomainRequest() {}
-// Reassign the original function. Now its writable attribute
-// should be true. Hackish, I know, but it works.
-XDomainRequest = sinon.xdr.XDomainRequest || undefined;
+ // Reassign the original function. Now its writable attribute
+ // should be true. Hackish, I know, but it works.
+ XDomainRequest = sinon.xdr.XDomainRequest || undefined;
+}
diff --git a/resources/src/dom-level2-skip.js b/resources/src/dom-level2-skip.js
new file mode 100644
index 00000000..484c295e
--- /dev/null
+++ b/resources/src/dom-level2-skip.js
@@ -0,0 +1,6 @@
+/*!
+ * Skip function for dom-level2-shim module.
+ *
+ * Tests for window.Node because that's the only thing that this shim is adding.
+ */
+return !!window.Node;
diff --git a/resources/src/jquery.tipsy/jquery.tipsy.js b/resources/src/jquery.tipsy/jquery.tipsy.js
index 2a37fa86..29b7490f 100644
--- a/resources/src/jquery.tipsy/jquery.tipsy.js
+++ b/resources/src/jquery.tipsy/jquery.tipsy.js
@@ -16,6 +16,7 @@
this.$element = $(element);
this.options = options;
this.enabled = true;
+ this.keyHandler = $.proxy( this.closeOnEsc, this );
this.fixTitle();
}
@@ -30,7 +31,10 @@
if (this.options.className) {
$tip.addClass(maybeCall(this.options.className, this.$element[0]));
}
- $tip.remove().css({top: 0, left: 0, visibility: 'hidden', display: 'block'}).appendTo(document.body);
+ $tip.remove()
+ .css({top: 0, left: 0, visibility: 'hidden', display: 'block'})
+ .attr( 'aria-hidden', 'true' )
+ .appendTo(document.body);
var pos = $.extend({}, this.$element.offset(), {
width: this.$element[0].offsetWidth,
@@ -82,15 +86,22 @@
}
$tip.css(tp);
+ $( document ).on( 'keydown', this.keyHandler );
if (this.options.fade) {
- $tip.stop().css({opacity: 0, display: 'block', visibility: 'visible'}).animate({opacity: this.options.opacity}, 100);
+ $tip.stop()
+ .css({opacity: 0, display: 'block', visibility: 'visible'})
+ .attr( 'aria-hidden', 'false' )
+ .animate({opacity: this.options.opacity}, 100);
} else {
- $tip.css({visibility: 'visible', opacity: this.options.opacity});
+ $tip
+ .css({visibility: 'visible', opacity: this.options.opacity})
+ .attr( 'aria-hidden', 'false' );
}
}
},
hide: function() {
+ $( document ).off( 'keydown', this.keyHandler );
if (this.options.fade) {
this.tip().stop().fadeOut(100, function() { $(this).remove(); });
} else {
@@ -120,7 +131,7 @@
tip: function() {
if (!this.$tip) {
- this.$tip = $('<div class="tipsy"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>');
+ this.$tip = $('<div class="tipsy" role="tooltip"></div>').html('<div class="tipsy-arrow"></div><div class="tipsy-inner"></div>');
}
return this.$tip;
},
@@ -133,6 +144,13 @@
}
},
+ // $.proxy event handler
+ closeOnEsc: function ( e ) {
+ if ( e.keyCode === 27 ) {
+ this.hide();
+ }
+ },
+
enable: function() { this.enabled = true; },
disable: function() { this.enabled = false; },
toggleEnabled: function() { this.enabled = !this.enabled; }
@@ -183,8 +201,8 @@
if (!options.live) this.each(function() { get(this); });
if ( options.trigger != 'manual' ) {
- var eventIn = options.trigger == 'hover' ? 'mouseenter' : 'focus',
- eventOut = options.trigger == 'hover' ? 'mouseleave' : 'blur';
+ var eventIn = options.trigger == 'hover' ? 'mouseenter focus' : 'focus',
+ eventOut = options.trigger == 'hover' ? 'mouseleave blur' : 'blur';
if ( options.live ) {
mw.track( 'mw.deprecate', 'tipsy-live' );
mw.log.warn( 'Use of the "live" option of jquery.tipsy is deprecated.' );
diff --git a/resources/src/jquery/jquery.accessKeyLabel.js b/resources/src/jquery/jquery.accessKeyLabel.js
index 867c25e7..92f8eb9c 100644
--- a/resources/src/jquery/jquery.accessKeyLabel.js
+++ b/resources/src/jquery/jquery.accessKeyLabel.js
@@ -112,7 +112,7 @@ function getAccessKeyLabel( element ) {
*/
function updateTooltipOnElement( element, titleElement ) {
var array = ( mw.msg( 'word-separator' ) + mw.msg( 'brackets' ) ).split( '$1' ),
- regexp = new RegExp( $.map( array, $.escapeRE ).join( '.*?' ) + '$' ),
+ regexp = new RegExp( $.map( array, mw.RegExp.escape ).join( '.*?' ) + '$' ),
oldTitle = titleElement.title,
rawTitle = oldTitle.replace( regexp, '' ),
newTitle = rawTitle,
@@ -150,14 +150,14 @@ function updateTooltip( element ) {
if ( id ) {
$label = $( 'label[for="' + id + '"]' );
if ( $label.length === 1 ) {
- updateTooltipOnElement( element, $label[0] );
+ updateTooltipOnElement( element, $label[ 0 ] );
}
}
// Search it as parent, because the form control can also be inside the label element itself
$labelParent = $element.parents( 'label' );
if ( $labelParent.length === 1 ) {
- updateTooltipOnElement( element, $labelParent[0] );
+ updateTooltipOnElement( element, $labelParent[ 0 ] );
}
}
}
diff --git a/resources/src/jquery/jquery.autoEllipsis.js b/resources/src/jquery/jquery.autoEllipsis.js
index 9a196b5d..e1115d65 100644
--- a/resources/src/jquery/jquery.autoEllipsis.js
+++ b/resources/src/jquery/jquery.autoEllipsis.js
@@ -69,16 +69,16 @@ $.fn.autoEllipsis = function ( options ) {
// Try cache
if ( options.matchText ) {
if ( !( text in matchTextCache ) ) {
- matchTextCache[text] = {};
+ matchTextCache[ text ] = {};
}
- if ( !( options.matchText in matchTextCache[text] ) ) {
- matchTextCache[text][options.matchText] = {};
+ if ( !( options.matchText in matchTextCache[ text ] ) ) {
+ matchTextCache[ text ][ options.matchText ] = {};
}
- if ( !( w in matchTextCache[text][options.matchText] ) ) {
- matchTextCache[text][options.matchText][w] = {};
+ if ( !( w in matchTextCache[ text ][ options.matchText ] ) ) {
+ matchTextCache[ text ][ options.matchText ][ w ] = {};
}
- if ( options.position in matchTextCache[text][options.matchText][w] ) {
- $container.html( matchTextCache[text][options.matchText][w][options.position] );
+ if ( options.position in matchTextCache[ text ][ options.matchText ][ w ] ) {
+ $container.html( matchTextCache[ text ][ options.matchText ][ w ][ options.position ] );
if ( options.tooltip ) {
$container.attr( 'title', text );
}
@@ -86,13 +86,13 @@ $.fn.autoEllipsis = function ( options ) {
}
} else {
if ( !( text in cache ) ) {
- cache[text] = {};
+ cache[ text ] = {};
}
- if ( !( w in cache[text] ) ) {
- cache[text][w] = {};
+ if ( !( w in cache[ text ] ) ) {
+ cache[ text ][ w ] = {};
}
- if ( options.position in cache[text][w] ) {
- $container.html( cache[text][w][options.position] );
+ if ( options.position in cache[ text ][ w ] ) {
+ $container.html( cache[ text ][ w ][ options.position ] );
if ( options.tooltip ) {
$container.attr( 'title', text );
}
@@ -120,19 +120,19 @@ $.fn.autoEllipsis = function ( options ) {
break;
case 'center':
// TODO: Use binary search like for 'right'
- i = [Math.round( trimmableText.length / 2 ), Math.round( trimmableText.length / 2 )];
+ i = [ Math.round( trimmableText.length / 2 ), Math.round( trimmableText.length / 2 ) ];
// Begin with making the end shorter
side = 1;
- while ( $trimmableText.outerWidth() + pw > w && i[0] > 0 ) {
- $trimmableText.text( trimmableText.slice( 0, i[0] ) + '...' + trimmableText.slice( i[1] ) );
+ while ( $trimmableText.outerWidth() + pw > w && i[ 0 ] > 0 ) {
+ $trimmableText.text( trimmableText.slice( 0, i[ 0 ] ) + '...' + trimmableText.slice( i[ 1 ] ) );
// Alternate between trimming the end and begining
if ( side === 0 ) {
// Make the begining shorter
- i[0]--;
+ i[ 0 ]--;
side = 1;
} else {
// Make the end shorter
- i[1]++;
+ i[ 1 ]++;
side = 0;
}
}
@@ -152,9 +152,9 @@ $.fn.autoEllipsis = function ( options ) {
}
if ( options.matchText ) {
$container.highlightText( options.matchText );
- matchTextCache[text][options.matchText][w][options.position] = $container.html();
+ matchTextCache[ text ][ options.matchText ][ w ][ options.position ] = $container.html();
} else {
- cache[text][w][options.position] = $container.html();
+ cache[ text ][ w ][ options.position ] = $container.html();
}
} );
diff --git a/resources/src/jquery/jquery.byteLimit.js b/resources/src/jquery/jquery.byteLimit.js
index 5551232a..dd71a2bc 100644
--- a/resources/src/jquery/jquery.byteLimit.js
+++ b/resources/src/jquery/jquery.byteLimit.js
@@ -10,17 +10,17 @@
* "fobo", not "foba". Basically emulating the native maxlength by
* reconstructing where the insertion occurred.
*
- * @private
+ * @static
* @param {string} safeVal Known value that was previously returned by this
* function, if none, pass empty string.
* @param {string} newVal New value that may have to be trimmed down.
* @param {number} byteLimit Number of bytes the value may be in size.
- * @param {Function} [fn] See jQuery.byteLimit.
+ * @param {Function} [fn] See jQuery#byteLimit.
* @return {Object}
* @return {string} return.newVal
* @return {boolean} return.trimmed
*/
- function trimValForByteLength( safeVal, newVal, byteLimit, fn ) {
+ $.trimByteLength = function ( safeVal, newVal, byteLimit, fn ) {
var startMatches, endMatches, matchesLen, inpParts,
oldVal = safeVal;
@@ -77,22 +77,22 @@
// until the limit is statisfied.
if ( fn ) {
// stop, when there is nothing to slice - bug 41450
- while ( $.byteLength( fn( inpParts.join( '' ) ) ) > byteLimit && inpParts[1].length > 0 ) {
- inpParts[1] = inpParts[1].slice( 0, -1 );
+ while ( $.byteLength( fn( inpParts.join( '' ) ) ) > byteLimit && inpParts[ 1 ].length > 0 ) {
+ inpParts[ 1 ] = inpParts[ 1 ].slice( 0, -1 );
}
} else {
while ( $.byteLength( inpParts.join( '' ) ) > byteLimit ) {
- inpParts[1] = inpParts[1].slice( 0, -1 );
+ inpParts[ 1 ] = inpParts[ 1 ].slice( 0, -1 );
}
}
- newVal = inpParts.join( '' );
-
return {
- newVal: newVal,
- trimmed: true
+ newVal: inpParts.join( '' ),
+ // For pathological fn() that always returns a value longer than the limit, we might have
+ // ended up not trimming - check for this case to avoid infinite loops
+ trimmed: newVal !== inpParts.join( '' )
};
- }
+ };
var eventKeys = [
'keyup.byteLimit',
@@ -206,7 +206,7 @@
// See http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboard-event-order for
// the order and characteristics of the key events.
$el.on( eventKeys, function () {
- var res = trimValForByteLength(
+ var res = $.trimByteLength(
prevSafeVal,
this.value,
elLimit,
@@ -219,9 +219,12 @@
// This is a side-effect of limiting after the fact.
if ( res.trimmed === true ) {
this.value = res.newVal;
+ // Trigger a 'change' event to let other scripts attached to this node know that the value
+ // was changed. This will also call ourselves again, but that's okay, it'll be a no-op.
+ $el.trigger( 'change' );
}
// Always adjust prevSafeVal to reflect the input value. Not doing this could cause
- // trimValForByteLength to compare the new value to an empty string instead of the
+ // trimByteLength to compare the new value to an empty string instead of the
// old value, resulting in trimming always from the end (bug 40850).
prevSafeVal = res.newVal;
} );
diff --git a/resources/src/jquery/jquery.color.js b/resources/src/jquery/jquery.color.js
index 04f8047b..a3cc8fc3 100644
--- a/resources/src/jquery/jquery.color.js
+++ b/resources/src/jquery/jquery.color.js
@@ -28,7 +28,7 @@
}
// We override the animation for all of these color styles
- $.each([
+ $.each( [
'backgroundColor',
'borderBottomColor',
'borderLeftColor',
@@ -37,17 +37,17 @@
'color',
'outlineColor'
], function ( i, attr ) {
- $.fx.step[attr] = function ( fx ) {
+ $.fx.step[ attr ] = function ( fx ) {
if ( !fx.colorInit ) {
fx.start = getColor( fx.elem, attr );
fx.end = $.colorUtil.getRGB( fx.end );
fx.colorInit = true;
}
- fx.elem.style[attr] = 'rgb(' + [
- Math.max( Math.min( parseInt( (fx.pos * (fx.end[0] - fx.start[0])) + fx.start[0], 10 ), 255 ), 0 ),
- Math.max( Math.min( parseInt( (fx.pos * (fx.end[1] - fx.start[1])) + fx.start[1], 10 ), 255 ), 0 ),
- Math.max( Math.min( parseInt( (fx.pos * (fx.end[2] - fx.start[2])) + fx.start[2], 10 ), 255 ), 0 )
+ fx.elem.style[ attr ] = 'rgb(' + [
+ Math.max( Math.min( parseInt( ( fx.pos * ( fx.end[ 0 ] - fx.start[ 0 ] ) ) + fx.start[ 0 ], 10 ), 255 ), 0 ),
+ Math.max( Math.min( parseInt( ( fx.pos * ( fx.end[ 1 ] - fx.start[ 1 ] ) ) + fx.start[ 1 ], 10 ), 255 ), 0 ),
+ Math.max( Math.min( parseInt( ( fx.pos * ( fx.end[ 2 ] - fx.start[ 2 ] ) ) + fx.start[ 2 ], 10 ), 255 ), 0 )
].join( ',' ) + ')';
};
} );
diff --git a/resources/src/jquery/jquery.colorUtil.js b/resources/src/jquery/jquery.colorUtil.js
index a6ff8bc8..c14f2c86 100644
--- a/resources/src/jquery/jquery.colorUtil.js
+++ b/resources/src/jquery/jquery.colorUtil.js
@@ -32,48 +32,48 @@
}
// Look for rgb(num,num,num)
- if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(color)) {
+ if ( result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec( color ) ) {
return [
- parseInt( result[1], 10 ),
- parseInt( result[2], 10 ),
- parseInt( result[3], 10 )
+ parseInt( result[ 1 ], 10 ),
+ parseInt( result[ 2 ], 10 ),
+ parseInt( result[ 3 ], 10 )
];
}
// Look for rgb(num%,num%,num%)
- if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(color)) {
+ if ( result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec( color ) ) {
return [
- parseFloat( result[1] ) * 2.55,
- parseFloat( result[2] ) * 2.55,
- parseFloat( result[3] ) * 2.55
+ parseFloat( result[ 1 ] ) * 2.55,
+ parseFloat( result[ 2 ] ) * 2.55,
+ parseFloat( result[ 3 ] ) * 2.55
];
}
// Look for #a0b1c2
- if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(color)) {
+ if ( result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec( color ) ) {
return [
- parseInt( result[1], 16 ),
- parseInt( result[2], 16 ),
- parseInt( result[3], 16 )
+ parseInt( result[ 1 ], 16 ),
+ parseInt( result[ 2 ], 16 ),
+ parseInt( result[ 3 ], 16 )
];
}
// Look for #fff
- if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(color)) {
+ if ( result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec( color ) ) {
return [
- parseInt( result[1] + result[1], 16 ),
- parseInt( result[2] + result[2], 16 ),
- parseInt( result[3] + result[3], 16)
+ parseInt( result[ 1 ] + result[ 1 ], 16 ),
+ parseInt( result[ 2 ] + result[ 2 ], 16 ),
+ parseInt( result[ 3 ] + result[ 3 ], 16 )
];
}
// Look for rgba(0, 0, 0, 0) == transparent in Safari 3
- if (result = /rgba\(0, 0, 0, 0\)/.exec(color)) {
+ if ( result = /rgba\(0, 0, 0, 0\)/.exec( color ) ) {
return $.colorUtil.colors.transparent;
}
// Otherwise, we're most likely dealing with a named color
- return $.colorUtil.colors[$.trim(color).toLowerCase()];
+ return $.colorUtil.colors[ $.trim( color ).toLowerCase() ];
},
/**
@@ -85,50 +85,50 @@
* @property {Object}
*/
colors: {
- aqua: [0, 255, 255],
- azure: [240, 255, 255],
- beige: [245, 245, 220],
- black: [0, 0, 0],
- blue: [0, 0, 255],
- brown: [165, 42, 42],
- cyan: [0, 255, 255],
- darkblue: [0, 0, 139],
- darkcyan: [0, 139, 139],
- darkgrey: [169, 169, 169],
- darkgreen: [0, 100, 0],
- darkkhaki: [189, 183, 107],
- darkmagenta: [139, 0, 139],
- darkolivegreen: [85, 107, 47],
- darkorange: [255, 140, 0],
- darkorchid: [153, 50, 204],
- darkred: [139, 0, 0],
- darksalmon: [233, 150, 122],
- darkviolet: [148, 0, 211],
- fuchsia: [255, 0, 255],
- gold: [255, 215, 0],
- green: [0, 128, 0],
- indigo: [75, 0, 130],
- khaki: [240, 230, 140],
- lightblue: [173, 216, 230],
- lightcyan: [224, 255, 255],
- lightgreen: [144, 238, 144],
- lightgrey: [211, 211, 211],
- lightpink: [255, 182, 193],
- lightyellow: [255, 255, 224],
- lime: [0, 255, 0],
- magenta: [255, 0, 255],
- maroon: [128, 0, 0],
- navy: [0, 0, 128],
- olive: [128, 128, 0],
- orange: [255, 165, 0],
- pink: [255, 192, 203],
- purple: [128, 0, 128],
- violet: [128, 0, 128],
- red: [255, 0, 0],
- silver: [192, 192, 192],
- white: [255, 255, 255],
- yellow: [255, 255, 0],
- transparent: [255, 255, 255]
+ aqua: [ 0, 255, 255 ],
+ azure: [ 240, 255, 255 ],
+ beige: [ 245, 245, 220 ],
+ black: [ 0, 0, 0 ],
+ blue: [ 0, 0, 255 ],
+ brown: [ 165, 42, 42 ],
+ cyan: [ 0, 255, 255 ],
+ darkblue: [ 0, 0, 139 ],
+ darkcyan: [ 0, 139, 139 ],
+ darkgrey: [ 169, 169, 169 ],
+ darkgreen: [ 0, 100, 0 ],
+ darkkhaki: [ 189, 183, 107 ],
+ darkmagenta: [ 139, 0, 139 ],
+ darkolivegreen: [ 85, 107, 47 ],
+ darkorange: [ 255, 140, 0 ],
+ darkorchid: [ 153, 50, 204 ],
+ darkred: [ 139, 0, 0 ],
+ darksalmon: [ 233, 150, 122 ],
+ darkviolet: [ 148, 0, 211 ],
+ fuchsia: [ 255, 0, 255 ],
+ gold: [ 255, 215, 0 ],
+ green: [ 0, 128, 0 ],
+ indigo: [ 75, 0, 130 ],
+ khaki: [ 240, 230, 140 ],
+ lightblue: [ 173, 216, 230 ],
+ lightcyan: [ 224, 255, 255 ],
+ lightgreen: [ 144, 238, 144 ],
+ lightgrey: [ 211, 211, 211 ],
+ lightpink: [ 255, 182, 193 ],
+ lightyellow: [ 255, 255, 224 ],
+ lime: [ 0, 255, 0 ],
+ magenta: [ 255, 0, 255 ],
+ maroon: [ 128, 0, 0 ],
+ navy: [ 0, 0, 128 ],
+ olive: [ 128, 128, 0 ],
+ orange: [ 255, 165, 0 ],
+ pink: [ 255, 192, 203 ],
+ purple: [ 128, 0, 128 ],
+ violet: [ 128, 0, 128 ],
+ red: [ 255, 0, 0 ],
+ silver: [ 192, 192, 192 ],
+ white: [ 255, 255, 255 ],
+ yellow: [ 255, 255, 0 ],
+ transparent: [ 255, 255, 255 ]
},
/**
@@ -157,29 +157,29 @@
min = Math.min( r, g, b ),
h,
s,
- l = (max + min) / 2;
+ l = ( max + min ) / 2;
if ( max === min ) {
// achromatic
h = s = 0;
} else {
d = max - min;
- s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+ s = l > 0.5 ? d / ( 2 - max - min ) : d / ( max + min );
switch ( max ) {
case r:
- h = (g - b) / d + (g < b ? 6 : 0);
+ h = ( g - b ) / d + ( g < b ? 6 : 0 );
break;
case g:
- h = (b - r) / d + 2;
+ h = ( b - r ) / d + 2;
break;
case b:
- h = (r - g) / d + 4;
+ h = ( r - g ) / d + 4;
break;
}
h /= 6;
}
- return [h, s, l];
+ return [ h, s, l ];
},
/**
@@ -212,25 +212,25 @@
t -= 1;
}
if ( t < 1 / 6 ) {
- return p + (q - p) * 6 * t;
+ return p + ( q - p ) * 6 * t;
}
if ( t < 1 / 2 ) {
return q;
}
if ( t < 2 / 3 ) {
- return p + (q - p) * (2 / 3 - t) * 6;
+ return p + ( q - p ) * ( 2 / 3 - t ) * 6;
}
return p;
};
- q = l < 0.5 ? l * (1 + s) : l + s - l * s;
+ q = l < 0.5 ? l * ( 1 + s ) : l + s - l * s;
p = 2 * l - q;
r = hue2rgb( p, q, h + 1 / 3 );
g = hue2rgb( p, q, h );
b = hue2rgb( p, q, h - 1 / 3 );
}
- return [r * 255, g * 255, b * 255];
+ return [ r * 255, g * 255, b * 255 ];
},
/**
@@ -249,11 +249,11 @@
*/
getColorBrightness: function ( currentColor, mod ) {
var rgbArr = $.colorUtil.getRGB( currentColor ),
- hslArr = $.colorUtil.rgbToHsl(rgbArr[0], rgbArr[1], rgbArr[2] );
- rgbArr = $.colorUtil.hslToRgb(hslArr[0], hslArr[1], hslArr[2] + mod);
+ hslArr = $.colorUtil.rgbToHsl( rgbArr[ 0 ], rgbArr[ 1 ], rgbArr[ 2 ] );
+ rgbArr = $.colorUtil.hslToRgb( hslArr[ 0 ], hslArr[ 1 ], hslArr[ 2 ] + mod );
return 'rgb(' +
- [parseInt( rgbArr[0], 10), parseInt( rgbArr[1], 10 ), parseInt( rgbArr[2], 10 )].join( ',' ) +
+ [ parseInt( rgbArr[ 0 ], 10 ), parseInt( rgbArr[ 1 ], 10 ), parseInt( rgbArr[ 2 ], 10 ) ].join( ',' ) +
')';
}
diff --git a/resources/src/jquery/jquery.expandableField.js b/resources/src/jquery/jquery.expandableField.js
index 48341bc5..221e6bbe 100644
--- a/resources/src/jquery/jquery.expandableField.js
+++ b/resources/src/jquery/jquery.expandableField.js
@@ -23,7 +23,7 @@
expandField: function ( e, context ) {
context.config.beforeExpand.call( context.data.$field, context );
context.data.$field
- .animate( { 'width': context.data.expandedWidth }, 'fast', function () {
+ .animate( { width: context.data.expandedWidth }, 'fast', function () {
context.config.afterExpand.call( this, context );
} );
},
@@ -33,18 +33,19 @@
condenseField: function ( e, context ) {
context.config.beforeCondense.call( context.data.$field, context );
context.data.$field
- .animate( { 'width': context.data.condensedWidth }, 'fast', function () {
+ .animate( { width: context.data.condensedWidth }, 'fast', function () {
context.config.afterCondense.call( this, context );
} );
},
/**
* 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 ) {
// TODO: Validate creation using fallback values
- context.config[property] = value;
+ context.config[ property ] = value;
}
};
@@ -87,20 +88,20 @@
/* API */
// Handle various calling styles
if ( args.length > 0 ) {
- if ( typeof args[0] === 'object' ) {
+ if ( typeof args[ 0 ] === 'object' ) {
// Apply set of properties
- for ( key in args[0] ) {
- $.expandableField.configure( context, key, args[0][key] );
+ for ( key in args[ 0 ] ) {
+ $.expandableField.configure( context, key, args[ 0 ][ key ] );
}
- } else if ( typeof args[0] === 'string' ) {
+ } else if ( typeof args[ 0 ] === 'string' ) {
if ( args.length > 1 ) {
// Set property values
- $.expandableField.configure( context, args[0], args[1] );
+ $.expandableField.configure( context, args[ 0 ], args[ 1 ] );
// TODO: Do we need to check both null and undefined?
} else if ( returnValue === null || returnValue === undefined ) {
// Get property values, but don't give access to internal data - returns only the first
- returnValue = ( args[0] in context.config ? undefined : context.config[args[0]] );
+ returnValue = ( args[ 0 ] in context.config ? undefined : context.config[ args[ 0 ] ] );
}
}
}
diff --git a/resources/src/jquery/jquery.farbtastic.js b/resources/src/jquery/jquery.farbtastic.js
index d7024cc8..f70913f9 100644
--- a/resources/src/jquery/jquery.farbtastic.js
+++ b/resources/src/jquery/jquery.farbtastic.js
@@ -52,10 +52,10 @@ jQuery._farbtastic = function (container, callback) {
if (this.currentStyle.backgroundImage != 'none') {
var image = this.currentStyle.backgroundImage;
image = this.currentStyle.backgroundImage.slice(5, image.length - 2);
- $(this).css({
- 'backgroundImage': 'none',
- 'filter': "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
- });
+ $(this).css( {
+ backgroundImage: 'none',
+ filter: "progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src='" + image + "')"
+ } );
}
});
}
diff --git a/resources/src/jquery/jquery.getAttrs.js b/resources/src/jquery/jquery.getAttrs.js
index 64827fb7..3064b423 100644
--- a/resources/src/jquery/jquery.getAttrs.js
+++ b/resources/src/jquery/jquery.getAttrs.js
@@ -8,7 +8,7 @@ function serializeControls( controls ) {
len = controls.length;
for ( i = 0; i < len; i++ ) {
- data[ controls[i].name ] = controls[i].value;
+ data[ controls[ i ].name ] = controls[ i ].value;
}
return data;
@@ -23,7 +23,7 @@ function serializeControls( controls ) {
* @return {Object}
*/
jQuery.fn.getAttrs = function () {
- return serializeControls( this[0].attributes );
+ return serializeControls( this[ 0 ].attributes );
};
/**
diff --git a/resources/src/jquery/jquery.hidpi.js b/resources/src/jquery/jquery.hidpi.js
index 8fca0567..aa6590bf 100644
--- a/resources/src/jquery/jquery.hidpi.js
+++ b/resources/src/jquery/jquery.hidpi.js
@@ -27,14 +27,15 @@
$.devicePixelRatio = function () {
if ( window.devicePixelRatio !== undefined ) {
// Most web browsers:
- // * WebKit (Safari, Chrome, Android browser, etc)
+ // * WebKit/Blink (Safari, Chrome, Android browser, etc)
// * Opera
// * Firefox 18+
+ // * Microsoft Edge (Windows 10)
return window.devicePixelRatio;
} else if ( window.msMatchMedia !== undefined ) {
// Windows 8 desktops / tablets, probably Windows Phone 8
//
- // IE 10 doesn't report pixel ratio directly, but we can get the
+ // IE 10/11 doesn't report pixel ratio directly, but we can get the
// screen DPI and divide by 96. We'll bracket to [1, 1.5, 2.0] for
// simplicity, but you may get different values depending on zoom
// factor, size of screen and orientation in Metro IE.
@@ -53,6 +54,52 @@ $.devicePixelRatio = function () {
};
/**
+ * Bracket a given device pixel ratio to one of [1, 1.5, 2].
+ *
+ * This is useful for grabbing images on the fly with sizes based on the display
+ * density, without causing slowdown and extra thumbnail renderings on devices
+ * that are slightly different from the most common sizes.
+ *
+ * The bracketed ratios match the default 'srcset' output on MediaWiki thumbnails,
+ * so will be consistent with default renderings.
+ *
+ * @static
+ * @inheritable
+ * @return {number} Device pixel ratio
+ */
+$.bracketDevicePixelRatio = function ( baseRatio ) {
+ if ( baseRatio > 1.5 ) {
+ return 2;
+ } else if ( baseRatio > 1 ) {
+ return 1.5;
+ } else {
+ return 1;
+ }
+};
+
+/**
+ * Get reported or approximate device pixel ratio, bracketed to [1, 1.5, 2].
+ *
+ * This is useful for grabbing images on the fly with sizes based on the display
+ * density, without causing slowdown and extra thumbnail renderings on devices
+ * that are slightly different from the most common sizes.
+ *
+ * The bracketed ratios match the default 'srcset' output on MediaWiki thumbnails,
+ * so will be consistent with default renderings.
+ *
+ * - 1.0 means 1 CSS pixel is 1 hardware pixel
+ * - 1.5 means 1 CSS pixel is 1.5 hardware pixels
+ * - 2.0 means 1 CSS pixel is 2 hardware pixels
+ *
+ * @static
+ * @inheritable
+ * @return {number} Device pixel ratio
+ */
+$.bracketedDevicePixelRatio = function () {
+ return $.bracketDevicePixelRatio( $.devicePixelRatio() );
+};
+
+/**
* Implement responsive images based on srcset attributes, if browser has no
* native srcset support.
*
@@ -106,11 +153,11 @@ $.matchSrcSet = function ( devicePixelRatio, srcset ) {
selectedSrc = null;
candidates = srcset.split( / *, */ );
for ( i = 0; i < candidates.length; i++ ) {
- candidate = candidates[i];
+ candidate = candidates[ i ];
bits = candidate.split( / +/ );
- src = bits[0];
- if ( bits.length > 1 && bits[1].charAt( bits[1].length - 1 ) === 'x' ) {
- ratioStr = bits[1].slice( 0, -1 );
+ src = bits[ 0 ];
+ if ( bits.length > 1 && bits[ 1 ].charAt( bits[ 1 ].length - 1 ) === 'x' ) {
+ ratioStr = bits[ 1 ].slice( 0, -1 );
ratio = parseFloat( ratioStr );
if ( ratio <= devicePixelRatio && ratio > selectedRatio ) {
selectedRatio = ratio;
diff --git a/resources/src/jquery/jquery.highlightText.js b/resources/src/jquery/jquery.highlightText.js
index 13382182..e37f19b0 100644
--- a/resources/src/jquery/jquery.highlightText.js
+++ b/resources/src/jquery/jquery.highlightText.js
@@ -3,7 +3,7 @@
* TODO: Add a function for restoring the previous text.
* TODO: Accept mappings for converting shortcuts like WP: to Wikipedia:.
*/
-( function ( $ ) {
+( function ( $, mw ) {
$.highlightText = {
@@ -12,10 +12,10 @@
var i,
patArray = pat.split( ' ' );
for ( i = 0; i < patArray.length; i++ ) {
- if ( patArray[i].length === 0 ) {
+ if ( patArray[ i ].length === 0 ) {
continue;
}
- $.highlightText.innerHighlight( node, patArray[i] );
+ $.highlightText.innerHighlight( node, patArray[ i ] );
}
return node;
},
@@ -23,15 +23,14 @@
// scans a node looking for the pattern and wraps a span around each match
innerHighlight: function ( node, pat ) {
var i, match, pos, spannode, middlebit, middleclone;
- // if this is a text node
- if ( node.nodeType === 3 ) {
+ if ( node.nodeType === Node.TEXT_NODE ) {
// TODO - need to be smarter about the character matching here.
// non latin characters can make regex think a new word has begun: do not use \b
// http://stackoverflow.com/questions/3787072/regex-wordwrap-with-utf8-characters-in-js
// look for an occurrence of our pattern and store the starting position
- match = node.data.match( new RegExp( '(^|\\s)' + $.escapeRE( pat ), 'i' ) );
+ match = node.data.match( new RegExp( '(^|\\s)' + mw.RegExp.escape( pat ), 'i' ) );
if ( match ) {
- pos = match.index + match[1].length; // include length of any matched spaces
+ pos = match.index + match[ 1 ].length; // include length of any matched spaces
// create the span wrapper for the matched text
spannode = document.createElement( 'span' );
spannode.className = 'highlight';
@@ -46,8 +45,8 @@
// replace the matched node, with our span-wrapped clone of the matched node
middlebit.parentNode.replaceChild( spannode, middlebit );
}
- // if this is an element with childnodes, and not a script, style or an element we created
- } else if ( node.nodeType === 1
+ } else if ( node.nodeType === Node.ELEMENT_NODE
+ // element with childnodes, and not a script, style or an element we created
&& node.childNodes
&& !/(script|style)/i.test( node.tagName )
&& !( node.tagName.toLowerCase() === 'span'
@@ -56,7 +55,7 @@
) {
for ( i = 0; i < node.childNodes.length; ++i ) {
// call the highlight function for each child node
- $.highlightText.innerHighlight( node.childNodes[i], pat );
+ $.highlightText.innerHighlight( node.childNodes[ i ], pat );
}
}
}
@@ -70,4 +69,4 @@
} );
};
-}( jQuery ) );
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/jquery/jquery.localize.js b/resources/src/jquery/jquery.localize.js
index 0b423545..f5932b24 100644
--- a/resources/src/jquery/jquery.localize.js
+++ b/resources/src/jquery/jquery.localize.js
@@ -5,16 +5,16 @@
/**
* Gets a localized message, using parameters from options if present.
- * @ignore
*
+ * @ignore
* @param {Object} options
* @param {string} key
* @return {string} Localized message
*/
function msg( options, key ) {
- var args = options.params[key] || [];
+ var args = options.params[ key ] || [];
// Format: mw.msg( key [, p1, p2, ...] )
- args.unshift( options.prefix + ( options.keys[key] || key ) );
+ args.unshift( options.prefix + ( options.keys[ key ] || key ) );
return mw.msg.apply( mw, args );
}
@@ -108,7 +108,7 @@ function msg( options, key ) {
*/
$.fn.localize = function ( options ) {
var $target = this,
- attributes = ['title', 'alt', 'placeholder'];
+ attributes = [ 'title', 'alt', 'placeholder' ];
// Extend options
options = $.extend( {
diff --git a/resources/src/jquery/jquery.makeCollapsible.js b/resources/src/jquery/jquery.makeCollapsible.js
index f7c42177..19fdb263 100644
--- a/resources/src/jquery/jquery.makeCollapsible.js
+++ b/resources/src/jquery/jquery.makeCollapsible.js
@@ -159,8 +159,13 @@
}
if ( e ) {
- if ( e.type === 'click' && options.linksPassthru && $.nodeName( e.target, 'a' ) ) {
- // Don't fire if a link was clicked, if requested (for premade togglers by default)
+ if (
+ e.type === 'click' &&
+ options.linksPassthru &&
+ $.nodeName( e.target, 'a' ) &&
+ $( e.target ).attr( 'href' ) !== '#'
+ ) {
+ // Don't fire if a link with href !== '#' was clicked, if requested (for premade togglers by default)
return;
} else if ( e.type === 'keypress' && e.which !== 13 && e.which !== 32 ) {
// Only handle keypresses on the "Enter" or "Space" keys
diff --git a/resources/src/jquery/jquery.mwExtension.js b/resources/src/jquery/jquery.mwExtension.js
index e6e33ade..27ceb2bc 100644
--- a/resources/src/jquery/jquery.mwExtension.js
+++ b/resources/src/jquery/jquery.mwExtension.js
@@ -1,9 +1,11 @@
/*
* JavaScript backwards-compatibility alternatives and other convenience functions
+ *
+ * @deprecated since 1.26 Dated collection of miscellaneous utilities. Methods are
+ * either trivially inline, obsolete, or have a better place elsewhere.
*/
-( function ( $ ) {
-
- $.extend( {
+( function ( $, mw ) {
+ $.each( {
trimLeft: function ( str ) {
return str === null ? '' : str.toString().replace( /^\s+/, '' );
},
@@ -14,9 +16,6 @@
ucFirst: function ( str ) {
return str.charAt( 0 ).toUpperCase() + str.slice( 1 );
},
- escapeRE: function ( str ) {
- return str.replace( /([\\{}()|.?*+\-\^$\[\]])/g, '\\$1' );
- },
isDomElement: function ( el ) {
return !!el && !!el.nodeType;
},
@@ -28,7 +27,7 @@
return true;
}
// the for-loop could potentially contain prototypes
- // to avoid that we check it's length first
+ // to avoid that we check its length first
if ( v.length === 0 ) {
return true;
}
@@ -45,11 +44,11 @@
return false;
}
for ( var i = 0; i < arrThis.length; i++ ) {
- if ( $.isArray( arrThis[i] ) ) {
- if ( !$.compareArray( arrThis[i], arrAgainst[i] ) ) {
+ if ( $.isArray( arrThis[ i ] ) ) {
+ if ( !$.compareArray( arrThis[ i ], arrAgainst[ i ] ) ) {
return false;
}
- } else if ( arrThis[i] !== arrAgainst[i] ) {
+ } else if ( arrThis[ i ] !== arrAgainst[ i ] ) {
return false;
}
}
@@ -72,24 +71,24 @@
// Check if this property is also present in the other object
if ( prop in objectB ) {
// Compare the types of the properties
- type = typeof objectA[prop];
- if ( type === typeof objectB[prop] ) {
+ type = typeof objectA[ prop ];
+ if ( type === typeof objectB[ prop ] ) {
// Recursively check objects inside this one
switch ( type ) {
case 'object' :
- if ( !$.compareObject( objectA[prop], objectB[prop] ) ) {
+ if ( !$.compareObject( objectA[ prop ], objectB[ prop ] ) ) {
return false;
}
break;
case 'function' :
// Functions need to be strings to compare them properly
- if ( objectA[prop].toString() !== objectB[prop].toString() ) {
+ if ( objectA[ prop ].toString() !== objectB[ prop ].toString() ) {
return false;
}
break;
default:
// Strings, numbers
- if ( objectA[prop] !== objectB[prop] ) {
+ if ( objectA[ prop ] !== objectB[ prop ] ) {
return false;
}
break;
@@ -117,6 +116,12 @@
}
return true;
}
+ }, function ( key, value ) {
+ mw.log.deprecate( $, key, value );
} );
-}( jQuery ) );
+ mw.log.deprecate( $, 'escapeRE', function ( str ) {
+ return str.replace( /([\\{}()|.?*+\-\^$\[\]])/g, '\\$1' );
+ }, 'Use mediawiki.RegExp instead.' );
+
+} )( jQuery, mediaWiki );
diff --git a/resources/src/jquery/jquery.placeholder.js b/resources/src/jquery/jquery.placeholder.js
index d50422e2..9c18a919 100644
--- a/resources/src/jquery/jquery.placeholder.js
+++ b/resources/src/jquery/jquery.placeholder.js
@@ -13,23 +13,115 @@
* @version 2.1.0
* @license MIT
*/
-( function ($) {
+( function ( $ ) {
- var isInputSupported = 'placeholder' in document.createElement('input'),
- isTextareaSupported = 'placeholder' in document.createElement('textarea'),
+ var isInputSupported = 'placeholder' in document.createElement( 'input' ),
+ isTextareaSupported = 'placeholder' in document.createElement( 'textarea' ),
prototype = $.fn,
valHooks = $.valHooks,
propHooks = $.propHooks,
hooks,
placeholder;
- if (isInputSupported && isTextareaSupported) {
+ function safeActiveElement() {
+ // Avoid IE9 `document.activeElement` of death
+ // https://github.com/mathiasbynens/jquery-placeholder/pull/99
+ try {
+ return document.activeElement;
+ } catch ( err ) {}
+ }
+
+ function args( elem ) {
+ // Return an object of element attributes
+ var newAttrs = {},
+ rinlinejQuery = /^jQuery\d+$/;
+ $.each( elem.attributes, function ( i, attr ) {
+ if ( attr.specified && !rinlinejQuery.test( attr.name ) ) {
+ newAttrs[ attr.name ] = attr.value;
+ }
+ } );
+ return newAttrs;
+ }
+
+ function clearPlaceholder( event, value ) {
+ var input = this,
+ $input = $( input );
+ if ( input.value === $input.attr( 'placeholder' ) && $input.hasClass( 'placeholder' ) ) {
+ if ( $input.data( 'placeholder-password' ) ) {
+ $input = $input.hide().next().show().attr( 'id', $input.removeAttr( 'id' ).data( 'placeholder-id' ) );
+ // If `clearPlaceholder` was called from `$.valHooks.input.set`
+ if ( event === true ) {
+ $input[ 0 ].value = value;
+ return value;
+ }
+ $input.focus();
+ } else {
+ input.value = '';
+ $input.removeClass( 'placeholder' );
+ if ( input === safeActiveElement() ) {
+ input.select();
+ }
+ }
+ }
+ }
- placeholder = prototype.placeholder = function (text) {
+ function setPlaceholder() {
+ var $replacement,
+ input = this,
+ $input = $( input ),
+ id = this.id;
+ if ( !input.value ) {
+ if ( input.type === 'password' ) {
+ if ( !$input.data( 'placeholder-textinput' ) ) {
+ try {
+ $replacement = $input.clone().attr( { type: 'text' } );
+ } catch ( e ) {
+ $replacement = $( '<input>' ).attr( $.extend( args( this ), { type: 'text' } ) );
+ }
+ $replacement
+ .removeAttr( 'name' )
+ .data( {
+ 'placeholder-password': $input,
+ 'placeholder-id': id
+ } )
+ .bind( 'focus.placeholder drop.placeholder', clearPlaceholder );
+ $input
+ .data( {
+ 'placeholder-textinput': $replacement,
+ 'placeholder-id': id
+ } )
+ .before( $replacement );
+ }
+ $input = $input.removeAttr( 'id' ).hide().prev().attr( 'id', id ).show();
+ // Note: `$input[0] != input` now!
+ }
+ $input.addClass( 'placeholder' );
+ $input[ 0 ].value = $input.attr( 'placeholder' );
+ } else {
+ $input.removeClass( 'placeholder' );
+ }
+ }
+
+ function changePlaceholder( text ) {
+ var hasArgs = arguments.length,
+ $input = this;
+ if ( hasArgs ) {
+ if ( $input.attr( 'placeholder' ) !== text ) {
+ $input.prop( 'placeholder', text );
+ if ( $input.hasClass( 'placeholder' ) ) {
+ $input[ 0 ].value = text;
+ }
+ }
+ }
+ }
+
+ if ( isInputSupported && isTextareaSupported ) {
+
+ placeholder = prototype.placeholder = function ( text ) {
var hasArgs = arguments.length;
- if (hasArgs) {
- changePlaceholder.call(this, text);
+ if ( hasArgs ) {
+ changePlaceholder.call( this, text );
}
return this;
@@ -39,25 +131,25 @@
} else {
- placeholder = prototype.placeholder = function (text) {
+ placeholder = prototype.placeholder = function ( text ) {
var $this = this,
hasArgs = arguments.length;
- if (hasArgs) {
- changePlaceholder.call(this, text);
+ if ( hasArgs ) {
+ changePlaceholder.call( this, text );
}
$this
- .filter((isInputSupported ? 'textarea' : ':input') + '[placeholder]')
+ .filter( ( isInputSupported ? 'textarea' : ':input' ) + '[placeholder]' )
.filter( function () {
- return !$(this).data('placeholder-enabled');
- })
- .bind({
+ return !$( this ).data( 'placeholder-enabled' );
+ } )
+ .bind( {
'focus.placeholder drop.placeholder': clearPlaceholder,
'blur.placeholder': setPlaceholder
- })
- .data('placeholder-enabled', true)
- .trigger('blur.placeholder');
+ } )
+ .data( 'placeholder-enabled', true )
+ .trigger( 'blur.placeholder' );
return $this;
};
@@ -65,36 +157,36 @@
placeholder.textarea = isTextareaSupported;
hooks = {
- 'get': function (element) {
- var $element = $(element),
- $passwordInput = $element.data('placeholder-password');
- if ($passwordInput) {
- return $passwordInput[0].value;
+ get: function ( element ) {
+ var $element = $( element ),
+ $passwordInput = $element.data( 'placeholder-password' );
+ if ( $passwordInput ) {
+ return $passwordInput[ 0 ].value;
}
- return $element.data('placeholder-enabled') && $element.hasClass('placeholder') ? '' : element.value;
+ return $element.data( 'placeholder-enabled' ) && $element.hasClass( 'placeholder' ) ? '' : element.value;
},
- 'set': function (element, value) {
- var $element = $(element),
- $passwordInput = $element.data('placeholder-password');
- if ($passwordInput) {
- $passwordInput[0].value = value;
+ set: function ( element, value ) {
+ var $element = $( element ),
+ $passwordInput = $element.data( 'placeholder-password' );
+ if ( $passwordInput ) {
+ $passwordInput[ 0 ].value = value;
return value;
}
- if (!$element.data('placeholder-enabled')) {
+ if ( !$element.data( 'placeholder-enabled' ) ) {
element.value = value;
return value;
}
- if (!value) {
+ if ( !value ) {
element.value = value;
// Issue #56: Setting the placeholder causes problems if the element continues to have focus.
- if (element !== safeActiveElement()) {
+ if ( element !== safeActiveElement() ) {
// We can't use `triggerHandler` here because of dummy text/password inputs :(
- setPlaceholder.call(element);
+ setPlaceholder.call( element );
}
- } else if ($element.hasClass('placeholder')) {
- if (!clearPlaceholder.call(element, true, value)) {
+ } else if ( $element.hasClass( 'placeholder' ) ) {
+ if ( !clearPlaceholder.call( element, true, value ) ) {
element.value = value;
}
} else {
@@ -105,125 +197,32 @@
}
};
- if (!isInputSupported) {
+ if ( !isInputSupported ) {
valHooks.input = hooks;
propHooks.value = hooks;
}
- if (!isTextareaSupported) {
+ if ( !isTextareaSupported ) {
valHooks.textarea = hooks;
propHooks.value = hooks;
}
$( function () {
// Look for forms
- $(document).delegate('form', 'submit.placeholder', function () {
+ $( document ).delegate( 'form', 'submit.placeholder', function () {
// Clear the placeholder values so they don't get submitted
- var $inputs = $('.placeholder', this).each(clearPlaceholder);
+ var $inputs = $( '.placeholder', this ).each( clearPlaceholder );
setTimeout( function () {
- $inputs.each(setPlaceholder);
- }, 10);
- });
- });
+ $inputs.each( setPlaceholder );
+ }, 10 );
+ } );
+ } );
// Clear placeholder values upon page reload
- $(window).bind('beforeunload.placeholder', function () {
- $('.placeholder').each( function () {
+ $( window ).bind( 'beforeunload.placeholder', function () {
+ $( '.placeholder' ).each( function () {
this.value = '';
- });
- });
+ } );
+ } );
}
-
- function args(elem) {
- // Return an object of element attributes
- var newAttrs = {},
- rinlinejQuery = /^jQuery\d+$/;
- $.each(elem.attributes, function (i, attr) {
- if (attr.specified && !rinlinejQuery.test(attr.name)) {
- newAttrs[attr.name] = attr.value;
- }
- });
- return newAttrs;
- }
-
- function clearPlaceholder(event, value) {
- var input = this,
- $input = $(input);
- if (input.value === $input.attr('placeholder') && $input.hasClass('placeholder')) {
- if ($input.data('placeholder-password')) {
- $input = $input.hide().next().show().attr('id', $input.removeAttr('id').data('placeholder-id'));
- // If `clearPlaceholder` was called from `$.valHooks.input.set`
- if (event === true) {
- $input[0].value = value;
- return value;
- }
- $input.focus();
- } else {
- input.value = '';
- $input.removeClass('placeholder');
- if (input === safeActiveElement()) {
- input.select();
- }
- }
- }
- }
-
- function setPlaceholder() {
- var $replacement,
- input = this,
- $input = $(input),
- id = this.id;
- if (!input.value) {
- if (input.type === 'password') {
- if (!$input.data('placeholder-textinput')) {
- try {
- $replacement = $input.clone().attr({ 'type': 'text' });
- } catch (e) {
- $replacement = $('<input>').attr($.extend(args(this), { 'type': 'text' }));
- }
- $replacement
- .removeAttr('name')
- .data({
- 'placeholder-password': $input,
- 'placeholder-id': id
- })
- .bind('focus.placeholder drop.placeholder', clearPlaceholder);
- $input
- .data({
- 'placeholder-textinput': $replacement,
- 'placeholder-id': id
- })
- .before($replacement);
- }
- $input = $input.removeAttr('id').hide().prev().attr('id', id).show();
- // Note: `$input[0] != input` now!
- }
- $input.addClass('placeholder');
- $input[0].value = $input.attr('placeholder');
- } else {
- $input.removeClass('placeholder');
- }
- }
-
- function safeActiveElement() {
- // Avoid IE9 `document.activeElement` of death
- // https://github.com/mathiasbynens/jquery-placeholder/pull/99
- try {
- return document.activeElement;
- } catch (err) {}
- }
-
- function changePlaceholder(text) {
- var hasArgs = arguments.length,
- $input = this;
- if (hasArgs) {
- if ($input.attr('placeholder') !== text) {
- $input.prop('placeholder', text);
- if ($input.hasClass('placeholder')) {
- $input[0].value = text;
- }
- }
- }
- }
-
-}(jQuery));
+}( jQuery ) );
diff --git a/resources/src/jquery/jquery.qunit.completenessTest.js b/resources/src/jquery/jquery.qunit.completenessTest.js
index 556bf8c7..785b2738 100644
--- a/resources/src/jquery/jquery.qunit.completenessTest.js
+++ b/resources/src/jquery/jquery.qunit.completenessTest.js
@@ -51,14 +51,14 @@
/**
* CompletenessTest
- * @constructor
*
+ * @constructor
* @example
* var myTester = new CompletenessTest( myLib );
- * @param masterVariable {Object} The root variable that contains all object
+ * @param {Object} masterVariable The root variable that contains all object
* members. CompletenessTest will recursively traverse objects and keep track
* of all methods.
- * @param ignoreFn {Function} Optionally pass a function to filter out certain
+ * @param {Function} [ignoreFn] Optionally pass a function to filter out certain
* methods. Example: You may want to filter out instances of jQuery or some
* other constructor. Otherwise "missingTests" will include all methods that
* were not called from that instance.
@@ -132,7 +132,7 @@
elOutputWrapper.appendChild( elContainer );
util.each( style, function ( key, value ) {
- elOutputWrapper.style[key] = value;
+ elOutputWrapper.style[ key ] = value;
} );
return elOutputWrapper;
}
@@ -186,12 +186,12 @@
* Depending on the action it either injects our listener into the methods, or
* reads from our tracker and records which methods have not been called by the test suite.
*
- * @param currName {String|Null} Name of the given object member (Initially this is null).
- * @param currVar {mixed} The variable to check (initially an object,
+ * @param {String|Null} currName Name of the given object member (Initially this is null).
+ * @param {mixed} currVar The variable to check (initially an object,
* further down it could be anything).
- * @param masterVariable {Object} Throughout our interation, always keep track of the master/root.
+ * @param {Object} masterVariable Throughout our interation, always keep track of the master/root.
* Initially this is the same as currVar.
- * @param parentPathArray {Array} Array of names that indicate our breadcrumb path starting at
+ * @param {Array} parentPathArray Array of names that indicate our breadcrumb path starting at
* masterVariable. Not including currName.
*/
walkTheObject: function ( currObj, currName, masterVariable, parentPathArray ) {
@@ -201,7 +201,7 @@
if ( currName ) {
currPathArray.push( currName );
- currVal = currObj[currName];
+ currVal = currObj[ currName ];
} else {
currName = '(root)';
currVal = currObj;
@@ -258,12 +258,12 @@
* was called during the test suite (as far as the tracker knows).
* If not it adds it to missingTests.
*
- * @param fnName {String}
+ * @param {String} fnName
* @return {Boolean}
*/
hasTest: function ( fnName ) {
if ( !( fnName in this.methodCallTracker ) ) {
- this.missingTests[fnName] = true;
+ this.missingTests[ fnName ] = true;
return false;
}
return true;
@@ -275,9 +275,9 @@
* Injects a function (such as a spy that updates methodCallTracker when
* it's called) inside another function.
*
- * @param masterVariable {Object}
- * @param objectPathArray {Array}
- * @param injectFn {Function}
+ * @param {Object} masterVariable
+ * @param {Array} objectPathArray
+ * @param {Function} injectFn
*/
injectCheck: function ( obj, key, injectFn ) {
var spy,
@@ -291,8 +291,11 @@
// Make the spy inherit from the original so that its static methods are also
// visible in the spy (e.g. when we inject a check into mw.log, mw.log.warn
// must remain accessible).
+ // XXX: https://github.com/jshint/jshint/issues/2656
+ /*jshint ignore:start */
/*jshint proto:true */
spy.__proto__ = val;
+ /*jshint ignore:end */
// Objects are by reference, members (unless objects) are not.
obj[ key ] = spy;
diff --git a/resources/src/jquery/jquery.spinner.js b/resources/src/jquery/jquery.spinner.js
index 361d3e08..41c555b7 100644
--- a/resources/src/jquery/jquery.spinner.js
+++ b/resources/src/jquery/jquery.spinner.js
@@ -67,7 +67,7 @@
opts = $.extend( {}, defaults, opts );
- var $spinner = $( '<div>', { 'class': 'mw-spinner', 'title': '...' } );
+ var $spinner = $( '<div>', { 'class': 'mw-spinner', title: '...' } );
if ( opts.id !== undefined ) {
$spinner.attr( 'id', 'mw-spinner-' + opts.id );
}
diff --git a/resources/src/jquery/jquery.suggestions.js b/resources/src/jquery/jquery.suggestions.js
index 813c37ce..dc1c7794 100644
--- a/resources/src/jquery/jquery.suggestions.js
+++ b/resources/src/jquery/jquery.suggestions.js
@@ -53,6 +53,12 @@
* @param {Function} options.result.select Called in context of the suggestions-result-current element.
* @param {jQuery} options.result.select.$textbox
*
+ * @param {Object} [options.update] Set of callbacks for listening to a change in the text input.
+ *
+ * @param {Function} options.update.before Called right after the user changes the textbox text.
+ * @param {Function} options.update.after Called after results are updated either from the cache or
+ * the API as a result of the user input.
+ *
* @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.
@@ -83,7 +89,7 @@
* @param {boolean} [options.positionFromLeft] Sets `expandFrom=left`, for backwards
* compatibility.
*
- * @param {boolean} [options.highlightInput=false] Whether to hightlight matched portions of the
+ * @param {boolean} [options.highlightInput=false] Whether to highlight matched portions of the
* input or not.
*/
( function ( $ ) {
@@ -136,6 +142,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
*/
update: function ( context, delayed ) {
@@ -144,6 +151,10 @@ $.suggestions = {
cache = context.data.cache,
cacheHit;
+ if ( typeof context.config.update.before === 'function' ) {
+ context.config.update.before.call( context.data.$textbox );
+ }
+
// Only fetch if the value in the textbox changed and is not empty, or if the results were hidden
// if the textbox is empty then clear the result div, but leave other settings intouched
if ( val.length === 0 ) {
@@ -158,6 +169,9 @@ $.suggestions = {
if ( context.config.cache && hasOwn.call( cache, val ) ) {
if ( +new Date() - cache[ val ].timestamp < context.config.cacheMaxAge ) {
context.data.$textbox.suggestions( 'suggestions', cache[ val ].suggestions );
+ if ( typeof context.config.update.after === 'function' ) {
+ context.config.update.after.call( context.data.$textbox );
+ }
cacheHit = true;
} else {
// Cache expired
@@ -171,6 +185,9 @@ $.suggestions = {
function ( suggestions ) {
suggestions = suggestions.slice( 0, context.config.maxRows );
context.data.$textbox.suggestions( 'suggestions', suggestions );
+ if ( typeof context.config.update.after === 'function' ) {
+ context.config.update.after.call( context.data.$textbox );
+ }
if ( context.config.cache ) {
cache[ val ] = {
suggestions: suggestions,
@@ -213,6 +230,7 @@ $.suggestions = {
/**
* Sets the value of a property, and updates the widget accordingly
+ *
* @param {string} property Name of property
* @param {Mixed} value Value to set property with
*/
@@ -227,12 +245,13 @@ $.suggestions = {
case 'cancel':
case 'special':
case 'result':
+ case 'update':
case '$region':
case 'expandFrom':
- context.config[property] = value;
+ context.config[ property ] = value;
break;
case 'suggestions':
- context.config[property] = value;
+ context.config[ property ] = value;
// Update suggestions
if ( context.data !== undefined ) {
if ( context.data.$textbox.val().length === 0 ) {
@@ -260,7 +279,7 @@ $.suggestions = {
expandFrom = 'left';
// Catch invalid values, default to 'auto'
- } else if ( $.inArray( expandFrom, ['left', 'right', 'start', 'end', 'auto'] ) === -1 ) {
+ } else if ( $.inArray( expandFrom, [ 'left', 'right', 'start', 'end', 'auto' ] ) === -1 ) {
expandFrom = 'auto';
}
@@ -319,11 +338,11 @@ $.suggestions = {
expWidth = -1;
for ( i = 0; i < context.config.suggestions.length; i++ ) {
/*jshint loopfunc:true */
- text = context.config.suggestions[i];
+ text = context.config.suggestions[ i ];
$result = $( '<div>' )
.addClass( 'suggestions-result' )
.attr( 'rel', i )
- .data( 'text', context.config.suggestions[i] )
+ .data( 'text', context.config.suggestions[ i ] )
.mousemove( function () {
context.data.selectedWithMouse = true;
$.suggestions.highlight(
@@ -335,7 +354,7 @@ $.suggestions = {
.appendTo( $results );
// Allow custom rendering
if ( typeof context.config.result.render === 'function' ) {
- context.config.result.render.call( $result, context.config.suggestions[i], context );
+ context.config.result.render.call( $result, context.config.suggestions[ i ], context );
} else {
$result.text( text );
}
@@ -376,28 +395,29 @@ $.suggestions = {
}
break;
case 'maxRows':
- context.config[property] = Math.max( 1, Math.min( 100, value ) );
+ context.config[ property ] = Math.max( 1, Math.min( 100, value ) );
break;
case 'delay':
- context.config[property] = Math.max( 0, Math.min( 1200, value ) );
+ context.config[ property ] = Math.max( 0, Math.min( 1200, value ) );
break;
case 'cacheMaxAge':
- context.config[property] = Math.max( 1, value );
+ context.config[ property ] = Math.max( 1, value );
break;
case 'maxExpandFactor':
- context.config[property] = Math.max( 1, value );
+ context.config[ property ] = Math.max( 1, value );
break;
case 'cache':
case 'submitOnClick':
case 'positionFromLeft':
case 'highlightInput':
- context.config[property] = !!value;
+ context.config[ property ] = !!value;
break;
}
},
/**
* Highlight a result in the results table
+ *
* @param {jQuery|string} result `<tr>` to highlight, or 'prev' or 'next'
* @param {boolean} updateTextbox If true, put the suggestion in the textbox
*/
@@ -467,6 +487,7 @@ $.suggestions = {
/**
* Respond to keypress event
+ *
* @param {number} key Code of key pressed
*/
keypress: function ( e, context, key ) {
@@ -559,6 +580,7 @@ $.fn.suggestions = function () {
cancel: function () {},
special: {},
result: {},
+ update: {},
$region: $( this ),
suggestions: [],
maxRows: 10,
@@ -577,18 +599,18 @@ $.fn.suggestions = function () {
// Handle various calling styles
if ( args.length > 0 ) {
- if ( typeof args[0] === 'object' ) {
+ if ( typeof args[ 0 ] === 'object' ) {
// Apply set of properties
- for ( key in args[0] ) {
- $.suggestions.configure( context, key, args[0][key] );
+ for ( key in args[ 0 ] ) {
+ $.suggestions.configure( context, key, args[ 0 ][ key ] );
}
- } else if ( typeof args[0] === 'string' ) {
+ } else if ( typeof args[ 0 ] === 'string' ) {
if ( args.length > 1 ) {
// Set property values
- $.suggestions.configure( context, args[0], args[1] );
+ $.suggestions.configure( context, args[ 0 ], args[ 1 ] );
} else if ( returnValue === null || returnValue === undefined ) {
// Get property values, but don't give access to internal data - returns only the first
- returnValue = ( args[0] in context.config ? undefined : context.config[args[0]] );
+ returnValue = ( args[ 0 ] in context.config ? undefined : context.config[ args[ 0 ] ] );
}
}
}
diff --git a/resources/src/jquery/jquery.tablesorter.js b/resources/src/jquery/jquery.tablesorter.js
index ff5ff0a9..eaa138b9 100644
--- a/resources/src/jquery/jquery.tablesorter.js
+++ b/resources/src/jquery/jquery.tablesorter.js
@@ -8,7 +8,7 @@
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
- * Depends on mw.config (wgDigitTransformTable, wgDefaultDateFormat, wgContentLanguage)
+ * Depends on mw.config (wgDigitTransformTable, wgDefaultDateFormat, wgPageContentLanguage)
* and mw.language.months.
*
* Uses 'tableSorterCollation' in mw.config (if available)
@@ -70,8 +70,8 @@
var i,
len = parsers.length;
for ( i = 0; i < len; i++ ) {
- if ( parsers[i].id.toLowerCase() === name.toLowerCase() ) {
- return parsers[i];
+ if ( parsers[ i ].id.toLowerCase() === name.toLowerCase() ) {
+ return parsers[ i ];
}
}
return false;
@@ -95,8 +95,7 @@
return $node.attr( 'alt' ) || ''; // handle undefined alt
} else {
return $.map( $.makeArray( node.childNodes ), function ( elem ) {
- // 1 is for document.ELEMENT_NODE (the constant is undefined on old browsers)
- if ( elem.nodeType === 1 ) {
+ if ( elem.nodeType === Node.ELEMENT_NODE ) {
return getElementSortKey( elem );
} else {
return $.text( elem );
@@ -106,69 +105,83 @@
}
}
- function detectParserForColumn( table, rows, cellIndex ) {
+ function detectParserForColumn( table, rows, column ) {
var l = parsers.length,
+ cellIndex,
nodeValue,
// Start with 1 because 0 is the fallback parser
i = 1,
+ lastRowIndex = -1,
rowIndex = 0,
concurrent = 0,
+ empty = 0,
needed = ( rows.length > 4 ) ? 5 : rows.length;
while ( i < l ) {
- if ( rows[rowIndex] && rows[rowIndex].cells[cellIndex] ) {
- nodeValue = $.trim( getElementSortKey( rows[rowIndex].cells[cellIndex] ) );
+ if ( rows[ rowIndex ] ) {
+ if ( rowIndex !== lastRowIndex ) {
+ lastRowIndex = rowIndex;
+ cellIndex = $( rows[ rowIndex ] ).data( 'columnToCell' )[ column ];
+ nodeValue = $.trim( getElementSortKey( rows[ rowIndex ].cells[ cellIndex ] ) );
+ }
} else {
nodeValue = '';
}
if ( nodeValue !== '' ) {
- if ( parsers[i].is( nodeValue, table ) ) {
+ if ( parsers[ i ].is( nodeValue, table ) ) {
concurrent++;
rowIndex++;
if ( concurrent >= needed ) {
// Confirmed the parser for multiple cells, let's return it
- return parsers[i];
+ return parsers[ i ];
}
} else {
// Check next parser, reset rows
i++;
rowIndex = 0;
concurrent = 0;
+ empty = 0;
}
} else {
// Empty cell
+ empty++;
rowIndex++;
- if ( rowIndex > rows.length ) {
- rowIndex = 0;
+ if ( rowIndex >= rows.length ) {
+ if ( concurrent >= rows.length - empty ) {
+ // Confirmed the parser for all filled cells
+ return parsers[ i ];
+ }
+ // Check next parser, reset rows
i++;
+ rowIndex = 0;
+ concurrent = 0;
+ empty = 0;
}
}
}
// 0 is always the generic parser (text)
- return parsers[0];
+ return parsers[ 0 ];
}
function buildParserCache( table, $headers ) {
- var sortType, cells, len, i, parser,
- rows = table.tBodies[0].rows,
+ var sortType, len, j, parser,
+ rows = table.tBodies[ 0 ].rows,
+ config = $( table ).data( 'tablesorter' ).config,
parsers = [];
- if ( rows[0] ) {
-
- cells = rows[0].cells;
- len = cells.length;
-
- for ( i = 0; i < len; i++ ) {
+ if ( rows[ 0 ] ) {
+ len = config.columns;
+ for ( j = 0; j < len; j++ ) {
parser = false;
- sortType = $headers.eq( i ).data( 'sortType' );
+ sortType = $headers.eq( config.columnToHeader[ j ] ).data( 'sortType' );
if ( sortType !== undefined ) {
parser = getParserById( sortType );
}
if ( parser === false ) {
- parser = detectParserForColumn( table, rows, i );
+ parser = detectParserForColumn( table, rows, j );
}
parsers.push( parser );
@@ -181,33 +194,35 @@
function buildCache( table ) {
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,
+ totalRows = ( table.tBodies[ 0 ] && table.tBodies[ 0 ].rows.length ) || 0,
config = $( table ).data( 'tablesorter' ).config,
parsers = config.parsers,
+ len = parsers.length,
+ cellIndex,
cache = {
row: [],
normalized: []
};
- for ( i = 0; i < totalRows; ++i ) {
+ for ( i = 0; i < totalRows; i++ ) {
// Add the table data to main data array
- $row = $( table.tBodies[0].rows[i] );
+ $row = $( table.tBodies[ 0 ].rows[ i ] );
cols = [];
// if this is a child row, add it to the last row's children and
// continue to the next row
if ( $row.hasClass( config.cssChildRow ) ) {
- cache.row[cache.row.length - 1] = cache.row[cache.row.length - 1].add( $row );
+ cache.row[ cache.row.length - 1 ] = cache.row[ cache.row.length - 1 ].add( $row );
// go to the next for loop
continue;
}
cache.row.push( $row );
- for ( j = 0; j < totalCells; ++j ) {
- cols.push( parsers[j].format( getElementSortKey( $row[0].cells[j] ), table, $row[0].cells[j] ) );
+ for ( j = 0; j < len; j++ ) {
+ cellIndex = $row.data( 'columnToCell' )[ j ];
+ cols.push( parsers[ j ].format( getElementSortKey( $row[ 0 ].cells[ cellIndex ] ) ) );
}
cols.push( cache.normalized.length ); // add position for rowCache
@@ -223,20 +238,20 @@
row = cache.row,
normalized = cache.normalized,
totalRows = normalized.length,
- checkCell = ( normalized[0].length - 1 ),
+ checkCell = ( normalized[ 0 ].length - 1 ),
fragment = document.createDocumentFragment();
for ( i = 0; i < totalRows; i++ ) {
- pos = normalized[i][checkCell];
+ pos = normalized[ i ][ checkCell ];
- l = row[pos].length;
+ l = row[ pos ].length;
for ( j = 0; j < l; j++ ) {
- fragment.appendChild( row[pos][j] );
+ fragment.appendChild( row[ pos ][ j ] );
}
}
- table.tBodies[0].appendChild( fragment );
+ table.tBodies[ 0 ].appendChild( fragment );
$( table ).trigger( 'sortEnd.tablesorter' );
}
@@ -249,7 +264,8 @@
*
* After this, it will look at all rows at the bottom for footer rows
* And place these in a tfoot using similar rules.
- * @param $table jQuery object for a <table>
+ *
+ * @param {jQuery} $table object for a <table>
*/
function emulateTHeadAndFoot( $table ) {
var $thead, $tfoot, i, len,
@@ -270,26 +286,37 @@
$tfoot = $( '<tfoot>' );
len = $rows.length;
for ( i = len - 1; i >= 0; i-- ) {
- if ( $( $rows[i] ).children( 'td' ).length ) {
+ if ( $( $rows[ i ] ).children( 'td' ).length ) {
break;
}
- $tfoot.prepend( $( $rows[i] ) );
+ $tfoot.prepend( $( $rows[ i ] ) );
}
$table.append( $tfoot );
}
}
+ function uniqueElements( array ) {
+ var uniques = [];
+ $.each( array, function ( index, elem ) {
+ if ( elem !== undefined && $.inArray( elem, uniques ) === -1 ) {
+ uniques.push( elem );
+ }
+ } );
+ return uniques;
+ }
+
function buildHeaders( table, msg ) {
var config = $( table ).data( 'tablesorter' ).config,
maxSeen = 0,
colspanOffset = 0,
columns,
- i,
+ k,
$cell,
rowspan,
colspan,
headerCount,
longestTR,
+ headerIndex,
exploded,
$tableHeaders = $( [] ),
$tableRows = $( 'thead:eq(0) > tr', table );
@@ -308,7 +335,7 @@
colspan = Number( cell.colSpan );
// Skip the spots in the exploded matrix that are already filled
- while ( exploded[rowIndex] && exploded[rowIndex][columnIndex] !== undefined ) {
+ while ( exploded[ rowIndex ] && exploded[ rowIndex ][ columnIndex ] !== undefined ) {
++columnIndex;
}
@@ -316,10 +343,10 @@
// in the exploded matrix rowspan times colspan times, with the proper offsets
for ( matrixColumnIndex = columnIndex; matrixColumnIndex < columnIndex + colspan; ++matrixColumnIndex ) {
for ( matrixRowIndex = rowIndex; matrixRowIndex < rowIndex + rowspan; ++matrixRowIndex ) {
- if ( !exploded[matrixRowIndex] ) {
- exploded[matrixRowIndex] = [];
+ if ( !exploded[ matrixRowIndex ] ) {
+ exploded[ matrixRowIndex ] = [];
}
- exploded[matrixRowIndex][matrixColumnIndex] = cell;
+ exploded[ matrixRowIndex ][ matrixColumnIndex ] = cell;
}
}
} );
@@ -333,49 +360,65 @@
}
} );
// We cannot use $.unique() here because it sorts into dom order, which is undesirable
- $tableHeaders = $( uniqueElements( exploded[longestTR] ) ).filter( 'th' );
+ $tableHeaders = $( uniqueElements( exploded[ longestTR ] ) ).filter( 'th' );
}
// 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
- $tableHeaders.each( function ( headerIndex ) {
+ config.columnToHeader = [];
+ config.headerToColumns = [];
+ config.headerList = [];
+ headerIndex = 0;
+ $tableHeaders.each( function () {
$cell = $( this );
columns = [];
- for ( i = 0; i < this.colSpan; i++ ) {
- config.columnToHeader[ colspanOffset + i ] = headerIndex;
- columns.push( colspanOffset + i );
- }
-
- config.headerToColumns[ headerIndex ] = columns;
- colspanOffset += this.colSpan;
-
- $cell.data( {
- headerIndex: headerIndex,
- order: 0,
- count: 0
- } );
-
- if ( $cell.hasClass( config.unsortableClass ) ) {
- $cell.data( 'sortDisabled', true );
- }
-
- if ( !$cell.data( 'sortDisabled' ) ) {
+ if ( !$cell.hasClass( config.unsortableClass ) ) {
$cell
.addClass( config.cssHeader )
.prop( 'tabIndex', 0 )
.attr( {
role: 'columnheader button',
- title: msg[1]
+ title: msg[ 1 ]
} );
+
+ for ( k = 0; k < this.colSpan; k++ ) {
+ config.columnToHeader[ colspanOffset + k ] = headerIndex;
+ columns.push( colspanOffset + k );
+ }
+
+ config.headerToColumns[ headerIndex ] = columns;
+
+ $cell.data( {
+ headerIndex: headerIndex,
+ order: 0,
+ count: 0
+ } );
+
+ // add only sortable cells to headerList
+ config.headerList[ headerIndex ] = this;
+ headerIndex++;
}
- // add cell to headerList
- config.headerList[headerIndex] = this;
+ colspanOffset += this.colSpan;
} );
- return $tableHeaders;
+ // number of columns with extended colspan, inclusive unsortable
+ // parsers[j], cache[][j], columnToHeader[j], columnToCell[j] have so many elements
+ config.columns = colspanOffset;
+
+ return $tableHeaders.not( '.' + config.unsortableClass );
+ }
+ function isValueInArray( v, a ) {
+ var i,
+ len = a.length;
+ for ( i = 0; i < len; i++ ) {
+ if ( a[ i ][ 0 ] === v ) {
+ return true;
+ }
+ }
+ return false;
}
/**
@@ -391,7 +434,7 @@
$.each( headerToColumns, function ( headerIndex, columns ) {
$.each( columns, function ( i, columnIndex ) {
- var header = $headers[headerIndex],
+ var header = $headers[ headerIndex ],
$header = $( header );
if ( !isValueInArray( columnIndex, sortList ) ) {
@@ -403,10 +446,10 @@
} else {
// Column shall be sorted: Apply designated count and order.
$.each( sortList, function ( j, sortColumn ) {
- if ( sortColumn[0] === i ) {
+ if ( sortColumn[ 0 ] === i ) {
$header.data( {
- order: sortColumn[1],
- count: sortColumn[1] + 1
+ order: sortColumn[ 1 ],
+ count: sortColumn[ 1 ] + 1
} );
return false;
}
@@ -417,35 +460,14 @@
} );
}
- function isValueInArray( v, a ) {
- var i,
- len = a.length;
- for ( i = 0; i < len; i++ ) {
- if ( a[i][0] === v ) {
- return true;
- }
- }
- return false;
- }
-
- function uniqueElements( array ) {
- var uniques = [];
- $.each( array, function ( index, elem ) {
- if ( elem !== undefined && $.inArray( elem, uniques ) === -1 ) {
- uniques.push( elem );
- }
- } );
- return uniques;
- }
-
function setHeadersCss( table, $headers, list, css, msg, columnToHeader ) {
// Remove all header information and reset titles to default message
- $headers.removeClass( css[0] ).removeClass( css[1] ).attr( 'title', msg[1] );
+ $headers.removeClass( css[ 0 ] ).removeClass( css[ 1 ] ).attr( 'title', msg[ 1 ] );
for ( var i = 0; i < list.length; i++ ) {
- $headers.eq( columnToHeader[ list[i][0] ] )
- .addClass( css[ list[i][1] ] )
- .attr( 'title', msg[ list[i][1] ] );
+ $headers.eq( columnToHeader[ list[ i ][ 0 ] ] )
+ .addClass( css[ list[ i ][ 1 ] ] )
+ .attr( 'title', msg[ list[ i ][ 1 ] ] );
}
}
@@ -462,19 +484,19 @@
sortFn = [],
len = sortList.length;
for ( i = 0; i < len; i++ ) {
- sortFn[i] = ( sortList[i][1] ) ? sortTextDesc : sortText;
+ sortFn[ i ] = ( sortList[ i ][ 1 ] ) ? sortTextDesc : sortText;
}
cache.normalized.sort( function ( array1, array2 ) {
var i, col, ret;
for ( i = 0; i < len; i++ ) {
- col = sortList[i][0];
- ret = sortFn[i].call( this, array1[col], array2[col] );
+ col = sortList[ i ][ 0 ];
+ ret = sortFn[ i ].call( this, array1[ col ], array2[ col ] );
if ( ret !== 0 ) {
return ret;
}
}
// Fall back to index number column to ensure stable sort
- return sortText.call( this, array1[array1.length - 1], array2[array2.length - 1] );
+ return sortText.call( this, array1[ array1.length - 1 ], array2[ array2.length - 1 ] );
} );
return cache;
}
@@ -485,19 +507,19 @@
separatorTransformTable = mw.config.get( 'wgSeparatorTransformTable' ),
digitTransformTable = mw.config.get( 'wgDigitTransformTable' );
- if ( separatorTransformTable === null || ( separatorTransformTable[0] === '' && digitTransformTable[2] === '' ) ) {
+ if ( separatorTransformTable === null || ( separatorTransformTable[ 0 ] === '' && digitTransformTable[ 2 ] === '' ) ) {
ts.transformTable = false;
} else {
ts.transformTable = {};
// Unpack the transform table
- ascii = separatorTransformTable[0].split( '\t' ).concat( digitTransformTable[0].split( '\t' ) );
- localised = separatorTransformTable[1].split( '\t' ).concat( digitTransformTable[1].split( '\t' ) );
+ ascii = separatorTransformTable[ 0 ].split( '\t' ).concat( digitTransformTable[ 0 ].split( '\t' ) );
+ localised = separatorTransformTable[ 1 ].split( '\t' ).concat( digitTransformTable[ 1 ].split( '\t' ) );
// Construct regex for number identification
for ( i = 0; i < ascii.length; i++ ) {
- ts.transformTable[localised[i]] = ascii[i];
- digits.push( $.escapeRE( localised[i] ) );
+ ts.transformTable[ localised[ i ] ] = ascii[ i ];
+ digits.push( mw.RegExp.escape( localised[ i ] ) );
}
}
digitClass = '[' + digits.join( '', digits ) + ']';
@@ -516,15 +538,15 @@
ts.monthNames = {};
for ( i = 0; i < 12; i++ ) {
- name = mw.language.months.names[i].toLowerCase();
- ts.monthNames[name] = i + 1;
- regex.push( $.escapeRE( name ) );
- name = mw.language.months.genitive[i].toLowerCase();
- ts.monthNames[name] = i + 1;
- regex.push( $.escapeRE( name ) );
- name = mw.language.months.abbrev[i].toLowerCase().replace( '.', '' );
- ts.monthNames[name] = i + 1;
- regex.push( $.escapeRE( name ) );
+ name = mw.language.months.names[ i ].toLowerCase();
+ ts.monthNames[ name ] = i + 1;
+ regex.push( mw.RegExp.escape( name ) );
+ name = mw.language.months.genitive[ i ].toLowerCase();
+ ts.monthNames[ name ] = i + 1;
+ regex.push( mw.RegExp.escape( name ) );
+ name = mw.language.months.abbrev[ i ].toLowerCase().replace( '.', '' );
+ ts.monthNames[ name ] = i + 1;
+ regex.push( mw.RegExp.escape( name ) );
}
// Build piped string
@@ -532,13 +554,13 @@
// Build RegEx
// Any date formated with . , ' - or /
- ts.dateRegex[0] = new RegExp( /^\s*(\d{1,2})[\,\.\-\/'\s]{1,2}(\d{1,2})[\,\.\-\/'\s]{1,2}(\d{2,4})\s*?/i );
+ ts.dateRegex[ 0 ] = new RegExp( /^\s*(\d{1,2})[\,\.\-\/'\s]{1,2}(\d{1,2})[\,\.\-\/'\s]{1,2}(\d{2,4})\s*?/i );
// Written Month name, dmy
- ts.dateRegex[1] = new RegExp( '^\\s*(\\d{1,2})[\\,\\.\\-\\/\'\\s]+(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]+(\\d{2,4})\\s*$', 'i' );
+ ts.dateRegex[ 1 ] = new RegExp( '^\\s*(\\d{1,2})[\\,\\.\\-\\/\'\\s]+(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]+(\\d{2,4})\\s*$', 'i' );
// Written Month name, mdy
- ts.dateRegex[2] = new RegExp( '^\\s*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]+(\\d{1,2})[\\,\\.\\-\\/\'\\s]+(\\d{2,4})\\s*$', 'i' );
+ ts.dateRegex[ 2 ] = new RegExp( '^\\s*(' + regex + ')' + '[\\,\\.\\-\\/\'\\s]+(\\d{1,2})[\\,\\.\\-\\/\'\\s]+(\\d{2,4})\\s*$', 'i' );
}
@@ -546,7 +568,7 @@
* Replace all rowspanned cells in the body with clones in each row, so sorting
* need not worry about them.
*
- * @param $table jQuery object for a <table>
+ * @param {jQuery} $table jQuery object for a <table>
*/
function explodeRowspans( $table ) {
var spanningRealCellIndex, rowSpan, colSpan,
@@ -566,11 +588,11 @@
col = 0,
l = this.cells.length;
for ( i = 0; i < l; i++ ) {
- $( this.cells[i] ).data( 'tablesorter', {
+ $( this.cells[ i ] ).data( 'tablesorter', {
realCellIndex: col,
realRowIndex: this.rowIndex
} );
- col += this.cells[i].colSpan;
+ col += this.cells[ i ].colSpan;
}
} );
@@ -609,7 +631,7 @@
}
while ( rowspanCells.length ) {
- if ( $.data( rowspanCells[0], 'tablesorter' ).needResort ) {
+ if ( $.data( rowspanCells[ 0 ], 'tablesorter' ).needResort ) {
resortCells();
}
@@ -621,7 +643,7 @@
cell.rowSpan = 1;
$nextRows = $( cell ).parent().nextAll();
for ( i = 0; i < rowSpan - 1; i++ ) {
- $tds = $( $nextRows[i].cells ).filter( filterfunc );
+ $tds = $( $nextRows[ i ].cells ).filter( filterfunc );
$clone = $( cell ).clone();
$clone.data( 'tablesorter', {
realCellIndex: spanningRealCellIndex,
@@ -638,6 +660,49 @@
}
}
+ /**
+ * Build index to handle colspanned cells in the body.
+ * Set the cell index for each column in an array,
+ * so that colspaned cells set multiple in this array.
+ * columnToCell[collumnIndex] point at the real cell in this row.
+ *
+ * @param {jQuery} $table object for a <table>
+ */
+ function manageColspans( $table ) {
+ var i, j, k, $row,
+ $rows = $table.find( '> tbody > tr' ),
+ totalRows = $rows.length || 0,
+ config = $table.data( 'tablesorter' ).config,
+ columns = config.columns,
+ columnToCell, cellsInRow, index;
+
+ for ( i = 0; i < totalRows; i++ ) {
+
+ $row = $rows.eq( i );
+ // if this is a child row, continue to the next row (as buildCache())
+ if ( $row.hasClass( config.cssChildRow ) ) {
+ // go to the next for loop
+ continue;
+ }
+
+ columnToCell = [];
+ cellsInRow = ( $row[ 0 ].cells.length ) || 0; // all cells in this row
+ index = 0; // real cell index in this row
+ for ( j = 0; j < columns; index++ ) {
+ if ( index === cellsInRow ) {
+ // Row with cells less than columns: add empty cell
+ $row.append( '<td>' );
+ cellsInRow++;
+ }
+ for ( k = 0; k < $row[ 0 ].cells[ index ].colSpan; k++ ) {
+ columnToCell[ j++ ] = index;
+ }
+ }
+ // Store it in $row
+ $row.data( 'columnToCell', columnToCell );
+ }
+ }
+
function buildCollationTable() {
ts.collationTable = mw.config.get( 'tableSorterCollation' );
ts.collationRegex = null;
@@ -699,7 +764,7 @@
$.each( sortObjects, function ( i, sortObject ) {
$.each( sortObject, function ( columnIndex, order ) {
var orderIndex = ( order === 'desc' ) ? 1 : 0;
- sortList.push( [parseInt( columnIndex, 10 ), orderIndex] );
+ sortList.push( [ parseInt( columnIndex, 10 ), orderIndex ] );
} );
} );
return sortList;
@@ -708,7 +773,6 @@
/* Public scope */
$.tablesorter = {
-
defaultOptions: {
cssHeader: 'headerSort',
cssAsc: 'headerSortUp',
@@ -716,20 +780,21 @@
cssChildRow: 'expand-child',
sortMultiSortKey: 'shiftKey',
unsortableClass: 'unsortable',
- parsers: {},
+ parsers: [],
cancelSelection: true,
sortList: [],
headerList: [],
headerToColumns: [],
- columnToHeader: []
+ columnToHeader: [],
+ columns: 0
},
dateRegex: [],
monthNames: {},
/**
- * @param $tables {jQuery}
- * @param settings {Object} (optional)
+ * @param {jQuery} $tables
+ * @param {Object} [settings]
*/
construct: function ( $tables, settings ) {
return $tables.each( function ( i, table ) {
@@ -799,6 +864,7 @@
}
explodeRowspans( $table );
+ manageColspans( $table );
// Try to auto detect column type, and store in tables config
config.parsers = buildParserCache( table, $headers );
@@ -806,7 +872,7 @@
// Apply event handling to headers
// this is too big, perhaps break it out?
- $headers.not( '.' + config.unsortableClass ).on( 'keypress click', function ( e ) {
+ $headers.on( 'keypress click', function ( e ) {
var cell, $cell, columns, newSortList, i,
totalRows,
j, s, o;
@@ -834,8 +900,8 @@
// cells get event .change() and bubbles up to the <table> here
cache = buildCache( table );
- totalRows = ( $table[0].tBodies[0] && $table[0].tBodies[0].rows.length ) || 0;
- if ( !table.sortDisabled && totalRows > 0 ) {
+ totalRows = ( $table[ 0 ].tBodies[ 0 ] && $table[ 0 ].tBodies[ 0 ].rows.length ) || 0;
+ if ( totalRows > 0 ) {
cell = this;
$cell = $( cell );
@@ -850,12 +916,12 @@
columns = config.headerToColumns[ $cell.data( 'headerIndex' ) ];
newSortList = $.map( columns, function ( c ) {
// jQuery "helpfully" flattens the arrays...
- return [[c, $cell.data( 'order' )]];
+ return [ [ c, $cell.data( 'order' ) ] ];
} );
// Index of first column belonging to this header
- i = columns[0];
+ i = columns[ 0 ];
- if ( !e[config.sortMultiSortKey] ) {
+ if ( !e[ config.sortMultiSortKey ] ) {
// User only wants to sort on one column set
// Flush the sort list and add new columns
config.sortList = newSortList;
@@ -867,11 +933,11 @@
// The user has clicked on an already sorted column.
// Reverse the sorting direction for all tables.
for ( j = 0; j < config.sortList.length; j++ ) {
- s = config.sortList[j];
- o = config.headerList[s[0]];
- if ( isValueInArray( s[0], newSortList ) ) {
- $( o ).data( 'count', s[1] + 1 );
- s[1] = $( o ).data( 'count' ) % 2;
+ s = config.sortList[ j ];
+ o = config.headerList[ config.columnToHeader[ s[ 0 ] ] ];
+ if ( isValueInArray( s[ 0 ], newSortList ) ) {
+ $( o ).data( 'count', s[ 1 ] + 1 );
+ s[ 1 ] = $( o ).data( 'count' ) % 2;
}
}
} else {
@@ -884,9 +950,9 @@
setHeadersOrder( $headers, config.sortList, config.headerToColumns );
// Set CSS for headers
- setHeadersCss( $table[0], $headers, config.sortList, sortCSS, sortMsg, config.columnToHeader );
+ setHeadersCss( $table[ 0 ], $headers, config.sortList, sortCSS, sortMsg, config.columnToHeader );
appendToTable(
- $table[0], multisort( $table[0], config.sortList, cache )
+ $table[ 0 ], multisort( $table[ 0 ], config.sortList, cache )
);
// Stop normal event by returning false
@@ -909,7 +975,7 @@
* Passing an empty array will reset sorting (basically just reset the headers
* making the table appear unsorted).
*
- * @param sortList {Array} (optional) List of sort objects.
+ * @param {Array} [sortList] List of sort objects.
*/
$table.data( 'tablesorter' ).sort = function ( sortList ) {
@@ -939,7 +1005,6 @@
// sort initially
if ( config.sortList.length > 0 ) {
- setupForFirstSort();
config.sortList = convertSortList( config.sortList );
$table.data( 'tablesorter' ).sort();
}
@@ -952,7 +1017,7 @@
len = parsers.length,
a = true;
for ( i = 0; i < len; i++ ) {
- if ( parsers[i].id.toLowerCase() === parser.id.toLowerCase() ) {
+ if ( parsers[ i ].id.toLowerCase() === parser.id.toLowerCase() ) {
a = false;
}
}
@@ -968,7 +1033,7 @@
for ( p = 0; p < s.length; p++ ) {
c = s.charAt( p );
if ( c in ts.transformTable ) {
- out += ts.transformTable[c];
+ out += ts.transformTable[ c ];
} else {
out += c;
}
@@ -990,7 +1055,7 @@
},
clearTableBody: function ( table ) {
- $( table.tBodies[0] ).empty();
+ $( table.tBodies[ 0 ] ).empty();
},
getParser: function ( id ) {
@@ -1000,6 +1065,10 @@
buildCollationTable();
return getParserById( id );
+ },
+
+ getParsers: function () { // for table diagnosis
+ return parsers;
}
};
@@ -1022,7 +1091,7 @@
if ( ts.collationRegex ) {
var tsc = ts.collationTable;
s = s.replace( ts.collationRegex, function ( match ) {
- var r = tsc[match] ? tsc[match] : tsc[match.toUpperCase()];
+ var r = tsc[ match ] ? tsc[ match ] : tsc[ match.toUpperCase() ];
return r.toLowerCase();
} );
}
@@ -1034,7 +1103,7 @@
ts.addParser( {
id: 'IPAddress',
is: function ( s ) {
- return ts.rgx.IPAddress[0].test( s );
+ return ts.rgx.IPAddress[ 0 ].test( s );
},
format: function ( s ) {
var i, item,
@@ -1042,7 +1111,7 @@
r = '',
len = a.length;
for ( i = 0; i < len; i++ ) {
- item = a[i];
+ item = a[ i ];
if ( item.length === 1 ) {
r += '00' + item;
} else if ( item.length === 2 ) {
@@ -1059,10 +1128,10 @@
ts.addParser( {
id: 'currency',
is: function ( s ) {
- return ts.rgx.currency[0].test( s );
+ return ts.rgx.currency[ 0 ].test( s );
},
format: function ( s ) {
- return $.tablesorter.formatDigit( s.replace( ts.rgx.currency[1], '' ) );
+ return $.tablesorter.formatDigit( s.replace( ts.rgx.currency[ 1 ], '' ) );
},
type: 'numeric'
} );
@@ -1070,10 +1139,10 @@
ts.addParser( {
id: 'url',
is: function ( s ) {
- return ts.rgx.url[0].test( s );
+ return ts.rgx.url[ 0 ].test( s );
},
format: function ( s ) {
- return $.trim( s.replace( ts.rgx.url[1], '' ) );
+ return $.trim( s.replace( ts.rgx.url[ 1 ], '' ) );
},
type: 'text'
} );
@@ -1081,7 +1150,7 @@
ts.addParser( {
id: 'isoDate',
is: function ( s ) {
- return ts.rgx.isoDate[0].test( s );
+ return ts.rgx.isoDate[ 0 ].test( s );
},
format: function ( s ) {
return $.tablesorter.formatFloat( ( s !== '' ) ? new Date( s.replace(
@@ -1093,7 +1162,7 @@
ts.addParser( {
id: 'usLongDate',
is: function ( s ) {
- return ts.rgx.usLongDate[0].test( s );
+ return ts.rgx.usLongDate[ 0 ].test( s );
},
format: function ( s ) {
return $.tablesorter.formatFloat( new Date( s ).getTime() );
@@ -1104,49 +1173,49 @@
ts.addParser( {
id: 'date',
is: function ( s ) {
- return ( ts.dateRegex[0].test( s ) || ts.dateRegex[1].test( s ) || ts.dateRegex[2].test( s ) );
+ return ( ts.dateRegex[ 0 ].test( s ) || ts.dateRegex[ 1 ].test( s ) || ts.dateRegex[ 2 ].test( s ) );
},
format: function ( s ) {
var match, y;
s = $.trim( s.toLowerCase() );
- if ( ( match = s.match( ts.dateRegex[0] ) ) !== null ) {
- if ( mw.config.get( 'wgDefaultDateFormat' ) === 'mdy' || mw.config.get( 'wgContentLanguage' ) === 'en' ) {
- s = [ match[3], match[1], match[2] ];
+ if ( ( match = s.match( ts.dateRegex[ 0 ] ) ) !== null ) {
+ if ( mw.config.get( 'wgDefaultDateFormat' ) === 'mdy' || mw.config.get( 'wgPageContentLanguage' ) === 'en' ) {
+ s = [ match[ 3 ], match[ 1 ], match[ 2 ] ];
} else if ( mw.config.get( 'wgDefaultDateFormat' ) === 'dmy' ) {
- s = [ match[3], match[2], match[1] ];
+ s = [ match[ 3 ], match[ 2 ], match[ 1 ] ];
} else {
// If we get here, we don't know which order the dd-dd-dddd
// date is in. So return something not entirely invalid.
return '99999999';
}
- } else if ( ( match = s.match( ts.dateRegex[1] ) ) !== null ) {
- s = [ match[3], String( ts.monthNames[match[2]] ), match[1] ];
- } else if ( ( match = s.match( ts.dateRegex[2] ) ) !== null ) {
- s = [ match[3], String( ts.monthNames[match[1]] ), match[2] ];
+ } else if ( ( match = s.match( ts.dateRegex[ 1 ] ) ) !== null ) {
+ s = [ match[ 3 ], String( ts.monthNames[ match[ 2 ] ] ), match[ 1 ] ];
+ } else if ( ( match = s.match( ts.dateRegex[ 2 ] ) ) !== null ) {
+ s = [ match[ 3 ], String( ts.monthNames[ match[ 1 ] ] ), match[ 2 ] ];
} else {
// Should never get here
return '99999999';
}
// Pad Month and Day
- if ( s[1].length === 1 ) {
- s[1] = '0' + s[1];
+ if ( s[ 1 ].length === 1 ) {
+ s[ 1 ] = '0' + s[ 1 ];
}
- if ( s[2].length === 1 ) {
- s[2] = '0' + s[2];
+ if ( s[ 2 ].length === 1 ) {
+ s[ 2 ] = '0' + s[ 2 ];
}
- if ( ( y = parseInt( s[0], 10 ) ) < 100 ) {
+ if ( ( y = parseInt( s[ 0 ], 10 ) ) < 100 ) {
// Guestimate years without centuries
if ( y < 30 ) {
- s[0] = 2000 + y;
+ s[ 0 ] = 2000 + y;
} else {
- s[0] = 1900 + y;
+ s[ 0 ] = 1900 + y;
}
}
- while ( s[0].length < 4 ) {
- s[0] = '0' + s[0];
+ while ( s[ 0 ].length < 4 ) {
+ s[ 0 ] = '0' + s[ 0 ];
}
return parseInt( s.join( '' ), 10 );
},
@@ -1156,7 +1225,7 @@
ts.addParser( {
id: 'time',
is: function ( s ) {
- return ts.rgx.time[0].test( s );
+ return ts.rgx.time[ 0 ].test( s );
},
format: function ( s ) {
return $.tablesorter.formatFloat( new Date( '2000/01/01 ' + s ).getTime() );
diff --git a/resources/src/jquery/jquery.textSelection.js b/resources/src/jquery/jquery.textSelection.js
index 51119305..b9016424 100644
--- a/resources/src/jquery/jquery.textSelection.js
+++ b/resources/src/jquery/jquery.textSelection.js
@@ -138,7 +138,7 @@
insertText = '',
selTextArr = selText.split( '\n' );
for ( i = 0; i < selTextArr.length; i++ ) {
- insertText += pre + selTextArr[i] + post;
+ insertText += pre + selTextArr[ i ] + post;
if ( i !== selTextArr.length - 1 ) {
insertText += '\n';
}
@@ -160,7 +160,7 @@
context.fn.restoreCursorAndScrollTop();
}
if ( options.selectionStart !== undefined ) {
- $( this ).textSelection( 'setSelection', { 'start': options.selectionStart, 'end': options.selectionEnd } );
+ $( this ).textSelection( 'setSelection', { start: options.selectionStart, end: options.selectionEnd } );
}
selText = $( this ).textSelection( 'getSelection' );
@@ -203,7 +203,7 @@
$( this ).focus();
if ( options.selectionStart !== undefined ) {
- $( this ).textSelection( 'setSelection', { 'start': options.selectionStart, 'end': options.selectionEnd } );
+ $( this ).textSelection( 'setSelection', { start: options.selectionStart, end: options.selectionEnd } );
}
selText = $( this ).textSelection( 'getSelection' );
@@ -411,7 +411,8 @@
*
* Scroll a textarea to the current cursor position. You can set the cursor
* position with setSelection()
- * @param options boolean Whether to force a scroll even if the caret position
+ *
+ * @param {boolean} options Whether to force a scroll even if the caret position
* is already visible. Defaults to false
*
* @fixme document the options parameters (function body suggests options.force is a boolean, not options itself)
@@ -576,7 +577,7 @@
context.fn.restoreSelection();
needSave = true;
}
- retval = ( alternateFn && alternateFn[command] || fn[command] ).call( this, options );
+ retval = ( alternateFn && alternateFn[ command ] || fn[ command ] ).call( this, options );
if ( hasWikiEditor && needSave ) {
context.fn.saveSelection();
}
diff --git a/resources/src/mediawiki.legacy/images/checker.png b/resources/src/mediawiki.action/images/checker.png
index 3e9e3d09..3e9e3d09 100644
--- a/resources/src/mediawiki.legacy/images/checker.png
+++ b/resources/src/mediawiki.action/images/checker.png
Binary files differ
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.collapsibleFooter.js b/resources/src/mediawiki.action/mediawiki.action.edit.collapsibleFooter.js
index 7ae51aba..011f9c55 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.collapsibleFooter.js
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.collapsibleFooter.js
@@ -1,27 +1,28 @@
-jQuery( document ).ready( function ( $ ) {
- var collapsibleLists, i, handleOne;
+( function ( mw ) {
+ var collapsibleLists, handleOne;
// Collapsible lists of categories and templates
collapsibleLists = [
{
- $list: $( '.templatesUsed ul' ),
- $toggler: $( '.mw-templatesUsedExplanation' ),
+ listSel: '.templatesUsed ul',
+ togglerSel: '.mw-templatesUsedExplanation',
cookieName: 'templates-used-list'
},
{
- $list: $( '.hiddencats ul' ),
- $toggler: $( '.mw-hiddenCategoriesExplanation' ),
+ listSel: '.hiddencats ul',
+ togglerSel: '.mw-hiddenCategoriesExplanation',
cookieName: 'hidden-categories-list'
},
{
- $list: $( '.preview-limit-report-wrapper' ),
- $toggler: $( '.mw-limitReportExplanation' ),
+ listSel: '.preview-limit-report-wrapper',
+ togglerSel: '.mw-limitReportExplanation',
cookieName: 'preview-limit-report'
}
];
handleOne = function ( $list, $toggler, cookieName ) {
- var isCollapsed = $.cookie( cookieName ) !== 'expanded';
+ // Collapsed by default
+ var isCollapsed = mw.cookie.get( cookieName ) !== 'expanded';
// Style the toggler with an arrow icon and add a tabIndex and a role for accessibility
$toggler.addClass( 'mw-editfooter-toggler' ).prop( 'tabIndex', 0 ).attr( 'role', 'button' );
@@ -38,17 +39,24 @@ jQuery( document ).ready( function ( $ ) {
$list.on( 'beforeExpand.mw-collapsible', function () {
$toggler.removeClass( 'mw-icon-arrow-collapsed' ).addClass( 'mw-icon-arrow-expanded' );
- $.cookie( cookieName, 'expanded' );
+ mw.cookie.set( cookieName, 'expanded' );
} );
$list.on( 'beforeCollapse.mw-collapsible', function () {
$toggler.removeClass( 'mw-icon-arrow-expanded' ).addClass( 'mw-icon-arrow-collapsed' );
- $.cookie( cookieName, 'collapsed' );
+ mw.cookie.set( cookieName, 'collapsed' );
} );
};
- for ( i = 0; i < collapsibleLists.length; i++ ) {
- // Pass to a function for iteration-local variables
- handleOne( collapsibleLists[i].$list, collapsibleLists[i].$toggler, collapsibleLists[i].cookieName );
- }
-} );
+ mw.hook( 'wikipage.editform' ).add( function ( $editForm ) {
+ var i;
+ for ( i = 0; i < collapsibleLists.length; i++ ) {
+ // Pass to a function for iteration-local variables
+ handleOne(
+ $editForm.find( collapsibleLists[ i ].listSel ),
+ $editForm.find( collapsibleLists[ i ].togglerSel ),
+ collapsibleLists[ i ].cookieName
+ );
+ }
+ } );
+}( mediaWiki ) );
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.css b/resources/src/mediawiki.action/mediawiki.action.edit.css
index 45ba5437..9b0c430c 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.css
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.css
@@ -7,9 +7,6 @@
height: 22px;
cursor: pointer;
vertical-align: middle;
- /* Cross-browser inline-block */
- /* Firefox 2 */
- display: -moz-inline-block;
/* Modern browsers */
display: inline-block;
/* IE7 */
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js b/resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js
index 6b330128..56dba703 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.editWarning.js
@@ -35,7 +35,7 @@
// Add form submission handler
$( '#editform' ).submit( function () {
- allowCloseWindow();
+ allowCloseWindow.release();
} );
} );
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.js b/resources/src/mediawiki.action/mediawiki.action.edit.js
index 01a25f3b..c9834f04 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.js
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.js
@@ -1,23 +1,40 @@
/*!
* Scripts for action=edit at domready
*/
-jQuery( function ( $ ) {
- var editBox, scrollTop, $editForm;
+( function ( mw, $ ) {
+ 'use strict';
- // Make sure edit summary does not exceed byte limit
- $( '#wpSummary' ).byteLimit( 255 );
+ /**
+ * Fired when the editform is added to the edit page
+ *
+ * Similar to the {@link mw.hook#event-wikipage_content wikipage.content hook}
+ * $editForm can still be detached when this hook is fired.
+ *
+ * @event wikipage_editform
+ * @member mw.hook
+ * @param {jQuery} $editForm The most appropriate element containing the
+ * editform, usually #editform.
+ */
- // 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;
+ $( 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' );
+ mw.hook( 'wikipage.editform' ).fire( $editForm );
+ if ( $editForm.length && editBox && scrollTop ) {
+ if ( scrollTop.value ) {
+ editBox.scrollTop = scrollTop.value;
+ }
+ $editForm.submit( function () {
+ scrollTop.value = editBox.scrollTop;
+ } );
}
- $editForm.submit( function () {
- scrollTop.value = editBox.scrollTop;
- } );
- }
-} );
+ } );
+}( 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 f24703af..ab4535b6 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.preview.js
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.preview.js
@@ -17,6 +17,7 @@
$editform = $( '#editform' );
$textbox = $editform.find( '#wpTextbox1' );
$summary = $editform.find( '#wpSummary' );
+ $spinner = $( '.mw-spinner-preview' );
$errorBox = $( '.errorbox' );
section = $editform.find( '[name="wpSection"]' ).val();
@@ -36,7 +37,7 @@
$wikiPreview.show();
// Jump to where the preview will appear
- $wikiPreview[0].scrollIntoView();
+ $wikiPreview[ 0 ].scrollIntoView();
copySelectors = [
// Main
@@ -55,14 +56,17 @@
// Not shown during normal preview, to be removed if present
$( '.mw-newarticletext' ).remove();
- $spinner = $.createSpinner( {
- size: 'large',
- type: 'block'
- } );
- $wikiPreview.before( $spinner );
- $spinner.css( {
- marginTop: $spinner.height()
- } );
+ if ( $spinner.length === 0 ) {
+ $spinner = $.createSpinner( {
+ size: 'large',
+ type: 'block'
+ } )
+ .addClass( 'mw-spinner-preview' )
+ .css( 'margin-top', '1em' );
+ $wikiPreview.before( $spinner );
+ } else {
+ $spinner.show();
+ }
// Can't use fadeTo because it calls show(), and we might want to keep some elements hidden
// (e.g. empty #catlinks)
@@ -98,7 +102,7 @@
indexpageids: '',
prop: 'revisions',
titles: mw.config.get( 'wgPageName' ),
- rvdifftotext: response.parse.text['*'],
+ rvdifftotext: response.parse.text[ '*' ],
rvprop: ''
};
if ( section !== '' ) {
@@ -106,8 +110,8 @@
}
return api.post( postData ).done( function ( result2 ) {
try {
- var diffHtml = result2.query.pages[result2.query.pageids[0]]
- .revisions[0].diff['*'];
+ 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
@@ -121,12 +125,15 @@
$.extend( postData, {
pst: '',
preview: '',
- prop: 'text|displaytitle|modules|categorieshtml|templates|langlinks|limitreporthtml',
+ prop: 'text|displaytitle|modules|jsconfigvars|categorieshtml|templates|langlinks|limitreporthtml',
disableeditsection: true
} );
request = api.post( postData );
request.done( function ( response ) {
var li, newList, $displaytitle, $content, $parent, $list;
+ if ( response.parse.jsconfigvars ) {
+ mw.config.set( response.parse.jsconfigvars );
+ }
if ( response.parse.modules ) {
mw.loader.load( response.parse.modules.concat(
response.parse.modulescripts,
@@ -148,7 +155,7 @@
);
}
if ( response.parse.categorieshtml ) {
- $( '#catlinks' ).replaceWith( response.parse.categorieshtml['*'] );
+ $( '#catlinks' ).replaceWith( response.parse.categorieshtml[ '*' ] );
}
if ( response.parse.templates ) {
newList = [];
@@ -156,10 +163,10 @@
li = $( '<li>' )
.append( $( '<a>' )
.attr( {
- 'href': mw.util.getUrl( template['*'] ),
+ href: mw.util.getUrl( template[ '*' ] ),
'class': ( template.exists !== undefined ? '' : 'new' )
} )
- .text( template['*'] )
+ .text( template[ '*' ] )
);
newList.push( li );
} );
@@ -167,7 +174,7 @@
$editform.find( '.templatesUsed .mw-editfooter-list' ).detach().empty().append( newList ).appendTo( '.templatesUsed' );
}
if ( response.parse.limitreporthtml ) {
- $( '.limitreport' ).html( response.parse.limitreporthtml['*'] );
+ $( '.limitreport' ).html( response.parse.limitreporthtml[ '*' ] );
}
if ( response.parse.langlinks && mw.config.get( 'skin' ) === 'vector' ) {
newList = [];
@@ -176,10 +183,10 @@
.addClass( 'interlanguage-link interwiki-' + langlink.lang )
.append( $( '<a>' )
.attr( {
- 'href': langlink.url,
- 'title': langlink['*'] + ' - ' + langlink.langname,
- 'lang': langlink.lang,
- 'hreflang': langlink.lang
+ href: langlink.url,
+ title: langlink[ '*' ] + ' - ' + langlink.langname,
+ lang: langlink.lang,
+ hreflang: langlink.lang
} )
.text( langlink.autonym )
);
@@ -190,11 +197,11 @@
$list.detach().empty().append( newList ).prependTo( $parent );
}
- if ( response.parse.text['*'] ) {
+ if ( response.parse.text[ '*' ] ) {
$content = $wikiPreview.children( '.mw-content-ltr,.mw-content-rtl' );
$content
.detach()
- .html( response.parse.text['*'] );
+ .html( response.parse.text[ '*' ] );
mw.hook( 'wikipage.content' ).fire( $content );
@@ -208,23 +215,23 @@
}
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['*'] )
- )
- );
+ summaryMsg = isSubject ? 'subject-preview' : 'summary-preview',
+ $summaryPreview = $editform.find( '.mw-summary-preview' ).empty();
+ if ( response.parse.parsedsummary && response.parse.parsedsummary[ '*' ] !== '' ) {
+ $summaryPreview.append(
+ mw.message( summaryMsg ).parse(),
+ ' ',
+ $( '<span>' ).addClass( 'comment' ).html(
+ // There is no equivalent to rawParams
+ mw.message( 'parentheses' ).escaped()
+ .replace( '$1', response.parse.parsedsummary[ '*' ] )
+ )
+ );
}
+ mw.hook( 'wikipage.editform' ).fire( $editform );
} );
request.always( function () {
- $spinner.remove();
+ $spinner.hide();
$copyElements.animate( {
opacity: 1
}, 'fast' );
@@ -265,9 +272,9 @@
$( '.portal:last' ).after(
$( '<div>' ).attr( {
'class': 'portal',
- 'id': 'p-lang',
- 'role': 'navigation',
- 'title': mw.msg( 'tooltip-p-lang' ),
+ 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' ) ) )
diff --git a/resources/src/mediawiki.action/mediawiki.action.edit.stash.js b/resources/src/mediawiki.action/mediawiki.action.edit.stash.js
index 29c533d8..abe912de 100644
--- a/resources/src/mediawiki.action/mediawiki.action.edit.stash.js
+++ b/resources/src/mediawiki.action/mediawiki.action.edit.stash.js
@@ -3,7 +3,7 @@
*/
( function ( mw, $ ) {
$( function () {
- var idleTimeout = 4000,
+ var idleTimeout = 3000,
api = new mw.Api(),
pending = null,
$form = $( '#editform' ),
diff --git a/resources/src/mediawiki.action/mediawiki.action.history.js b/resources/src/mediawiki.action/mediawiki.action.history.js
index 2ebfe921..077d5e3a 100644
--- a/resources/src/mediawiki.action/mediawiki.action.history.js
+++ b/resources/src/mediawiki.action/mediawiki.action.history.js
@@ -9,7 +9,7 @@ jQuery( function ( $ ) {
/**
* @ignore
* @context {Element} input
- * @param e {jQuery.Event}
+ * @param {jQuery.Event} e
*/
function updateDiffRadios() {
var nextState = 'before',
diff --git a/resources/src/mediawiki.action/mediawiki.action.view.filepage.css b/resources/src/mediawiki.action/mediawiki.action.view.filepage.css
new file mode 100644
index 00000000..bfc201af
--- /dev/null
+++ b/resources/src/mediawiki.action/mediawiki.action.view.filepage.css
@@ -0,0 +1,71 @@
+/*!
+ * File description page
+ */
+
+div.mw-filepage-resolutioninfo {
+ font-size: smaller;
+}
+
+/*
+ * File histories
+ */
+h2#filehistory {
+ clear: both;
+}
+
+table.filehistory th,
+table.filehistory td {
+ vertical-align: top;
+}
+
+table.filehistory th {
+ text-align: left;
+}
+
+table.filehistory td.mw-imagepage-filesize,
+table.filehistory th.mw-imagepage-filesize {
+ white-space: nowrap;
+}
+
+table.filehistory td.filehistory-selected {
+ font-weight: bold;
+}
+
+/*
+ * Add a checkered background image on hover for file
+ * description pages. (bug 26470)
+ */
+.filehistory a img,
+#file img:hover {
+ /* @embed */
+ background: white url(images/checker.png) repeat;
+}
+
+/*
+ * filetoc
+ */
+ul#filetoc {
+ text-align: center;
+ border: 1px solid #aaaaaa;
+ background-color: #f9f9f9;
+ padding: 5px;
+ font-size: 95%;
+ margin-bottom: 0.5em;
+ margin-left: 0;
+ margin-right: 0;
+}
+
+#filetoc li {
+ display: inline;
+ list-style-type: none;
+ padding-right: 2em;
+}
+
+/*
+ * Shared images hint
+ */
+#shared-image-dup,
+#shared-image-conflict {
+ font-style: italic;
+}
+
diff --git a/resources/src/mediawiki.action/mediawiki.action.view.filepage.print.css b/resources/src/mediawiki.action/mediawiki.action.view.filepage.print.css
new file mode 100644
index 00000000..15b20f10
--- /dev/null
+++ b/resources/src/mediawiki.action/mediawiki.action.view.filepage.print.css
@@ -0,0 +1,8 @@
+/*!
+ * File description page - print style
+ */
+
+span.mw-filepage-other-resolutions,
+#filetoc {
+ display: none;
+}
diff --git a/resources/src/mediawiki.action/mediawiki.action.view.metadata.css b/resources/src/mediawiki.action/mediawiki.action.view.metadata.css
index 9f786ecb..b07965ee 100644
--- a/resources/src/mediawiki.action/mediawiki.action.view.metadata.css
+++ b/resources/src/mediawiki.action/mediawiki.action.view.metadata.css
@@ -14,3 +14,9 @@ table.collapsed tr.collapsable {
-ms-user-select: none;
user-select: none;
}
+
+@media print {
+ tr.mw-metadata-show-hide-extended {
+ display: none;
+ }
+}
diff --git a/resources/src/mediawiki.action/mediawiki.action.view.postEdit.js b/resources/src/mediawiki.action/mediawiki.action.view.postEdit.js
index c008dfd8..168a1c18 100644
--- a/resources/src/mediawiki.action/mediawiki.action.view.postEdit.js
+++ b/resources/src/mediawiki.action/mediawiki.action.view.postEdit.js
@@ -24,6 +24,19 @@
cookieVal = mw.cookie.get( cookieKey ),
$div, id;
+ function removeConfirmation() {
+ $div.remove();
+ mw.hook( 'postEdit.afterRemoval' ).fire();
+ }
+
+ function fadeOutConfirmation() {
+ clearTimeout( id );
+ $div.find( '.postedit' ).addClass( 'postedit postedit-faded' );
+ setTimeout( removeConfirmation, 500 );
+
+ return false;
+ }
+
function showConfirmation( data ) {
data = data || {};
if ( data.message === undefined ) {
@@ -45,19 +58,6 @@
id = setTimeout( fadeOutConfirmation, 3000 );
}
- function fadeOutConfirmation() {
- clearTimeout( id );
- $div.find( '.postedit' ).addClass( 'postedit postedit-faded' );
- setTimeout( removeConfirmation, 500 );
-
- return false;
- }
-
- function removeConfirmation() {
- $div.remove();
- mw.hook( 'postEdit.afterRemoval' ).fire();
- }
-
mw.hook( 'postEdit' ).add( showConfirmation );
if ( config.wgAction === 'view' && cookieVal ) {
@@ -68,7 +68,7 @@
// postedit-confirmation-saved
// postedit-confirmation-created
// postedit-confirmation-restored
- 'message': mw.msg(
+ message: mw.msg(
'postedit-confirmation-' + cookieVal,
mw.user
)
diff --git a/resources/src/mediawiki.api/mediawiki.ForeignApi.js b/resources/src/mediawiki.api/mediawiki.ForeignApi.js
new file mode 100644
index 00000000..b8cc0598
--- /dev/null
+++ b/resources/src/mediawiki.api/mediawiki.ForeignApi.js
@@ -0,0 +1,109 @@
+( function ( mw, $ ) {
+
+ /**
+ * Create an object like mw.Api, but automatically handling everything required to communicate
+ * with another MediaWiki wiki via cross-origin requests (CORS).
+ *
+ * The foreign wiki must be configured to accept requests from the current wiki. See
+ * <https://www.mediawiki.org/wiki/Manual:$wgCrossSiteAJAXdomains> for details.
+ *
+ * var api = new mw.ForeignApi( 'https://commons.wikimedia.org/w/api.php' );
+ * api.get( {
+ * action: 'query',
+ * meta: 'userinfo'
+ * } ).done( function ( data ) {
+ * console.log( data );
+ * } );
+ *
+ * To ensure that the user at the foreign wiki is logged in, pass the `assert: 'user'` parameter
+ * to #get/#post (since MW 1.23): if they are not, the API request will fail. (Note that this
+ * doesn't guarantee that it's the same user.)
+ *
+ * Authentication-related MediaWiki extensions may extend this class to ensure that the user
+ * authenticated on the current wiki will be automatically authenticated on the foreign one. These
+ * extension modules should be registered using the ResourceLoaderForeignApiModules hook. See
+ * CentralAuth for a practical example. The general pattern to extend and override the name is:
+ *
+ * function MyForeignApi() {};
+ * OO.inheritClass( MyForeignApi, mw.ForeignApi );
+ * mw.ForeignApi = MyForeignApi;
+ *
+ * @class mw.ForeignApi
+ * @extends mw.Api
+ * @since 1.26
+ *
+ * @constructor
+ * @param {string|mw.Uri} url URL pointing to another wiki's `api.php` endpoint.
+ * @param {Object} [options] See mw.Api.
+ *
+ * @author Bartosz Dziewoński
+ * @author Jon Robson
+ */
+ function CoreForeignApi( url, options ) {
+ if ( !url || $.isPlainObject( url ) ) {
+ throw new Error( 'mw.ForeignApi() requires a `url` parameter' );
+ }
+
+ this.apiUrl = String( url );
+
+ options = $.extend( /*deep=*/ true,
+ {
+ ajax: {
+ url: this.apiUrl,
+ xhrFields: {
+ withCredentials: true
+ }
+ },
+ parameters: {
+ // Add 'origin' query parameter to all requests.
+ origin: this.getOrigin()
+ }
+ },
+ options
+ );
+
+ // Call parent constructor
+ CoreForeignApi.parent.call( this, options );
+ }
+
+ OO.inheritClass( CoreForeignApi, mw.Api );
+
+ /**
+ * Return the origin to use for API requests, in the required format (protocol, host and port, if
+ * any).
+ *
+ * @protected
+ * @return {string}
+ */
+ CoreForeignApi.prototype.getOrigin = function () {
+ var origin = location.protocol + '//' + location.hostname;
+ if ( location.port ) {
+ origin += ':' + location.port;
+ }
+ return origin;
+ };
+
+ /**
+ * @inheritdoc
+ */
+ CoreForeignApi.prototype.ajax = function ( parameters, ajaxOptions ) {
+ var url, origin, newAjaxOptions;
+
+ // 'origin' query parameter must be part of the request URI, and not just POST request body
+ if ( ajaxOptions.type === 'POST' ) {
+ url = ( ajaxOptions && ajaxOptions.url ) || this.defaults.ajax.url;
+ origin = ( parameters && parameters.origin ) || this.defaults.parameters.origin;
+ url += ( url.indexOf( '?' ) !== -1 ? '&' : '?' ) +
+ 'origin=' + encodeURIComponent( origin );
+ newAjaxOptions = $.extend( {}, ajaxOptions, { url: url } );
+ } else {
+ newAjaxOptions = ajaxOptions;
+ }
+
+ return CoreForeignApi.parent.prototype.ajax.call( this, parameters, newAjaxOptions );
+ };
+
+ // Expose
+ mw.ForeignApi = CoreForeignApi;
+
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.api/mediawiki.api.edit.js b/resources/src/mediawiki.api/mediawiki.api.edit.js
index dbe45bf6..e43285ff 100644
--- a/resources/src/mediawiki.api/mediawiki.api.edit.js
+++ b/resources/src/mediawiki.api/mediawiki.api.edit.js
@@ -11,10 +11,11 @@
* cached token and start over.
*
* @param {Object} params API parameters
+ * @param {Object} [ajaxOptions]
* @return {jQuery.Promise} See #post
*/
- postWithEditToken: function ( params ) {
- return this.postWithToken( 'edit', params );
+ postWithEditToken: function ( params, ajaxOptions ) {
+ return this.postWithToken( 'edit', params, ajaxOptions );
},
/**
@@ -30,6 +31,7 @@
/**
* Post a new section to the page.
+ *
* @see #postWithEditToken
* @param {mw.Title|String} title Target page
* @param {string} header
diff --git a/resources/src/mediawiki.api/mediawiki.api.js b/resources/src/mediawiki.api/mediawiki.api.js
index 3a19e021..73f3c8c6 100644
--- a/resources/src/mediawiki.api/mediawiki.api.js
+++ b/resources/src/mediawiki.api/mediawiki.api.js
@@ -1,26 +1,28 @@
( function ( mw, $ ) {
- // We allow people to omit these default parameters from API requests
- // there is very customizable error handling here, on a per-call basis
- // wondering, would it be simpler to make it easy to clone the api object,
- // change error handling, and use that instead?
- var defaultOptions = {
+ /**
+ * @class mw.Api
+ */
- // Query parameters for API requests
+ /**
+ * @property {Object} defaultOptions Default options for #ajax calls. Can be overridden by passing
+ * `options` to mw.Api constructor.
+ * @property {Object} defaultOptions.parameters Default query parameters for API requests.
+ * @property {Object} defaultOptions.ajax Default options for jQuery#ajax.
+ * @private
+ */
+ var defaultOptions = {
parameters: {
action: 'query',
format: 'json'
},
-
- // Ajax options for jQuery.ajax()
ajax: {
url: mw.util.wikiScript( 'api' ),
-
timeout: 30 * 1000, // 30 seconds
-
dataType: 'json'
}
},
+
// Keyed by ajax url and symbolic name for the individual request
promises = {};
@@ -39,37 +41,33 @@
* Constructor to create an object to interact with the API of a particular MediaWiki server.
* mw.Api objects represent the API of a particular MediaWiki server.
*
- * TODO: Share API objects with exact same config.
- *
* var api = new mw.Api();
* api.get( {
* action: 'query',
* meta: 'userinfo'
- * } ).done ( function ( data ) {
+ * } ).done( function ( data ) {
* console.log( data );
* } );
*
- * Multiple values for a parameter can be specified using an array (since MW 1.25):
+ * Since MW 1.25, multiple values for a parameter can be specified using an array:
*
* var api = new mw.Api();
* api.get( {
* action: 'query',
* meta: [ 'userinfo', 'siteinfo' ] // same effect as 'userinfo|siteinfo'
- * } ).done ( function ( data ) {
+ * } ).done( function ( data ) {
* console.log( data );
* } );
*
- * @class
+ * Since MW 1.26, boolean values for a parameter can be specified directly. If the value is
+ * `false` or `undefined`, the parameter will be omitted from the request, as required by the API.
*
* @constructor
- * @param {Object} options See defaultOptions documentation above. Ajax options can also be
- * overridden for each individual request to {@link jQuery#ajax} later on.
+ * @param {Object} [options] See #defaultOptions documentation above. Can also be overridden for
+ * each individual request by passing them to #get or #post (or directly #ajax) later on.
*/
mw.Api = function ( options ) {
-
- if ( options === undefined ) {
- options = {};
- }
+ options = options || {};
// Force a string if we got a mw.Uri object
if ( options.ajax && options.ajax.url !== undefined ) {
@@ -80,9 +78,22 @@
options.ajax = $.extend( {}, defaultOptions.ajax, options.ajax );
this.defaults = options;
+ this.requests = [];
};
mw.Api.prototype = {
+ /**
+ * Abort all unfinished requests issued by this Api object.
+ *
+ * @method
+ */
+ abort: function () {
+ $.each( this.requests, function ( index, request ) {
+ if ( request ) {
+ request.abort();
+ }
+ } );
+ },
/**
* Perform API get request
@@ -113,6 +124,27 @@
},
/**
+ * Massage parameters from the nice format we accept into a format suitable for the API.
+ *
+ * @private
+ * @param {Object} parameters (modified in-place)
+ */
+ preprocessParameters: function ( parameters ) {
+ var key;
+ // Handle common MediaWiki API idioms for passing parameters
+ for ( key in parameters ) {
+ // Multiple values are pipe-separated
+ if ( $.isArray( parameters[ key ] ) ) {
+ parameters[ key ] = parameters[ key ].join( '|' );
+ }
+ // Boolean values are only false when not given at all
+ if ( parameters[ key ] === false || parameters[ key ] === undefined ) {
+ delete parameters[ key ];
+ }
+ }
+ },
+
+ /**
* Perform the API call.
*
* @param {Object} parameters
@@ -121,7 +153,8 @@
* Fail: Error code
*/
ajax: function ( parameters, ajaxOptions ) {
- var token,
+ var token, requestIndex,
+ api = this,
apiDeferred = $.Deferred(),
xhr, key, formData;
@@ -134,11 +167,7 @@
delete parameters.token;
}
- for ( key in parameters ) {
- if ( $.isArray( parameters[key] ) ) {
- parameters[key] = parameters[key].join( '|' );
- }
- }
+ this.preprocessParameters( parameters );
// If multipart/form-data has been requested and emulation is possible, emulate it
if (
@@ -150,7 +179,7 @@
formData = new FormData();
for ( key in parameters ) {
- formData.append( key, parameters[key] );
+ formData.append( key, parameters[ key ] );
}
// If we extracted a token parameter, add it back in.
if ( token ) {
@@ -206,6 +235,11 @@
}
} );
+ requestIndex = this.requests.length;
+ this.requests.push( xhr );
+ xhr.always( function () {
+ api.requests[ requestIndex ] = null;
+ } );
// Return the Promise
return apiDeferred.promise( { abort: xhr.abort } ).fail( function ( code, details ) {
if ( !( code === 'http' && details && details.textStatus === 'abort' ) ) {
@@ -242,11 +276,9 @@
// Error handler
function ( code ) {
if ( code === 'badtoken' ) {
- // Clear from cache
- promises[ api.defaults.ajax.url ][ tokenType + 'Token' ] =
- params.token = undefined;
-
+ api.badToken( tokenType );
// Try again, once
+ params.token = undefined;
return api.getToken( tokenType, params.assert ).then( function ( token ) {
params.token = token;
return api.post( params, ajaxOptions );
@@ -281,17 +313,16 @@
d = apiPromise
.then( function ( data ) {
- // If token type is not available for this user,
- // key '...token' is either missing or set to boolean false
- if ( data.tokens && data.tokens[type + 'token'] ) {
- return data.tokens[type + 'token'];
+ if ( data.tokens && data.tokens[ type + 'token' ] ) {
+ return data.tokens[ type + 'token' ];
}
+ // If token type is not available for this user,
+ // key '...token' is either missing or set to boolean false
return $.Deferred().reject( 'token-missing', data );
}, function () {
// Clear promise. Do not cache errors.
delete promiseGroup[ type + 'Token' ];
-
// Pass on to allow the caller to handle the error
return this;
} )
@@ -306,6 +337,23 @@
}
return d;
+ },
+
+ /**
+ * Indicate that the cached token for a certain action of the API is bad.
+ *
+ * Call this if you get a 'badtoken' error when using the token returned by #getToken.
+ * You may also want to use #postWithToken instead, which invalidates bad cached tokens
+ * automatically.
+ *
+ * @param {string} type Token type
+ * @since 1.26
+ */
+ badToken: function ( type ) {
+ var promiseGroup = promises[ this.defaults.ajax.url ];
+ if ( promiseGroup ) {
+ delete promiseGroup[ type + 'Token' ];
+ }
}
};
diff --git a/resources/src/mediawiki.api/mediawiki.api.login.js b/resources/src/mediawiki.api/mediawiki.api.login.js
index 25257927..2b709aae 100644
--- a/resources/src/mediawiki.api/mediawiki.api.login.js
+++ b/resources/src/mediawiki.api/mediawiki.api.login.js
@@ -1,5 +1,6 @@
/**
* Make the two-step login easier.
+ *
* @author Niklas Laxström
* @class mw.Api.plugin.login
* @since 1.22
diff --git a/resources/src/mediawiki.api/mediawiki.api.options.js b/resources/src/mediawiki.api/mediawiki.api.options.js
index b839fbdc..399e6f43 100644
--- a/resources/src/mediawiki.api/mediawiki.api.options.js
+++ b/resources/src/mediawiki.api/mediawiki.api.options.js
@@ -14,7 +14,7 @@
*/
saveOption: function ( name, value ) {
var param = {};
- param[name] = value;
+ param[ name ] = value;
return this.saveOptions( param );
},
@@ -38,7 +38,7 @@
deferreds = [];
for ( name in options ) {
- value = options[name] === null ? null : String( options[name] );
+ value = options[ name ] === null ? null : String( options[ name ] );
// Can we bundle this option, or does it need a separate request?
bundleable =
diff --git a/resources/src/mediawiki.api/mediawiki.api.parse.js b/resources/src/mediawiki.api/mediawiki.api.parse.js
index 2dcf8078..bc3d44f9 100644
--- a/resources/src/mediawiki.api/mediawiki.api.parse.js
+++ b/resources/src/mediawiki.api/mediawiki.api.parse.js
@@ -21,7 +21,7 @@
return apiPromise
.then( function ( data ) {
- return data.parse.text['*'];
+ return data.parse.text[ '*' ];
} )
.promise( { abort: apiPromise.abort } );
}
diff --git a/resources/src/mediawiki.api/mediawiki.api.upload.js b/resources/src/mediawiki.api/mediawiki.api.upload.js
new file mode 100644
index 00000000..6f3e4c3f
--- /dev/null
+++ b/resources/src/mediawiki.api/mediawiki.api.upload.js
@@ -0,0 +1,391 @@
+/**
+ * Provides an interface for uploading files to MediaWiki.
+ *
+ * @class mw.Api.plugin.upload
+ * @singleton
+ */
+( function ( mw, $ ) {
+ var nonce = 0,
+ fieldsAllowed = {
+ stash: true,
+ filekey: true,
+ filename: true,
+ comment: true,
+ text: true,
+ watchlist: true,
+ ignorewarnings: true
+ };
+
+ /**
+ * @private
+ * Get nonce for iframe IDs on the page.
+ *
+ * @return {number}
+ */
+ function getNonce() {
+ return nonce++;
+ }
+
+ /**
+ * @private
+ * Given a non-empty object, return one of its keys.
+ *
+ * @param {Object} obj
+ * @return {string}
+ */
+ function getFirstKey( obj ) {
+ for ( var key in obj ) {
+ if ( obj.hasOwnProperty( key ) ) {
+ return key;
+ }
+ }
+ }
+
+ /**
+ * @private
+ * Get new iframe object for an upload.
+ *
+ * @return {HTMLIframeElement}
+ */
+ function getNewIframe( id ) {
+ var frame = document.createElement( 'iframe' );
+ frame.id = id;
+ frame.name = id;
+ return frame;
+ }
+
+ /**
+ * @private
+ * Shortcut for getting hidden inputs
+ *
+ * @return {jQuery}
+ */
+ function getHiddenInput( name, val ) {
+ return $( '<input type="hidden" />' )
+ .attr( 'name', name )
+ .val( val );
+ }
+
+ /**
+ * Process the result of the form submission, returned to an iframe.
+ * This is the iframe's onload event.
+ *
+ * @param {HTMLIframeElement} iframe Iframe to extract result from
+ * @return {Object} Response from the server. The return value may or may
+ * not be an XMLDocument, this code was copied from elsewhere, so if you
+ * see an unexpected return type, please file a bug.
+ */
+ function processIframeResult( iframe ) {
+ var json,
+ doc = iframe.contentDocument || frames[ iframe.id ].document;
+
+ if ( doc.XMLDocument ) {
+ // The response is a document property in IE
+ return doc.XMLDocument;
+ }
+
+ if ( doc.body ) {
+ // Get the json string
+ // We're actually searching through an HTML doc here --
+ // according to mdale we need to do this
+ // because IE does not load JSON properly in an iframe
+ json = $( doc.body ).find( 'pre' ).text();
+
+ return JSON.parse( json );
+ }
+
+ // Response is a xml document
+ return doc;
+ }
+
+ function formDataAvailable() {
+ return window.FormData !== undefined &&
+ window.File !== undefined &&
+ window.File.prototype.slice !== undefined;
+ }
+
+ $.extend( mw.Api.prototype, {
+ /**
+ * Upload a file to MediaWiki.
+ *
+ * The file will be uploaded using AJAX and FormData, if the browser supports it, or via an
+ * iframe if it doesn't.
+ *
+ * Caveats of iframe upload:
+ * - The returned jQuery.Promise will not receive `progress` notifications during the upload
+ * - It is incompatible with uploads to a foreign wiki using mw.ForeignApi
+ * - You must pass a HTMLInputElement and not a File for it to be possible
+ *
+ * @param {HTMLInputElement|File} file HTML input type=file element with a file already inside
+ * of it, or a File object.
+ * @param {Object} data Other upload options, see action=upload API docs for more
+ * @return {jQuery.Promise}
+ */
+ upload: function ( file, data ) {
+ var isFileInput, canUseFormData;
+
+ isFileInput = file && file.nodeType === Node.ELEMENT_NODE;
+
+ if ( formDataAvailable() && isFileInput && file.files ) {
+ file = file.files[ 0 ];
+ }
+
+ if ( !file ) {
+ throw new Error( 'No file' );
+ }
+
+ canUseFormData = formDataAvailable() && file instanceof window.File;
+
+ if ( !isFileInput && !canUseFormData ) {
+ throw new Error( 'Unsupported argument type passed to mw.Api.upload' );
+ }
+
+ if ( canUseFormData ) {
+ return this.uploadWithFormData( file, data );
+ }
+
+ return this.uploadWithIframe( file, data );
+ },
+
+ /**
+ * Upload a file to MediaWiki with an iframe and a form.
+ *
+ * This method is necessary for browsers without the File/FormData
+ * APIs, and continues to work in browsers with those APIs.
+ *
+ * The rough sketch of how this method works is as follows:
+ * 1. An iframe is loaded with no content.
+ * 2. A form is submitted with the passed-in file input and some extras.
+ * 3. The MediaWiki API receives that form data, and sends back a response.
+ * 4. The response is sent to the iframe, because we set target=(iframe id)
+ * 5. The response is parsed out of the iframe's document, and passed back
+ * through the promise.
+ *
+ * @private
+ * @param {HTMLInputElement} file The file input with a file in it.
+ * @param {Object} data Other upload options, see action=upload API docs for more
+ * @return {jQuery.Promise}
+ */
+ uploadWithIframe: function ( file, data ) {
+ var key,
+ tokenPromise = $.Deferred(),
+ api = this,
+ deferred = $.Deferred(),
+ nonce = getNonce(),
+ id = 'uploadframe-' + nonce,
+ $form = $( '<form>' ),
+ iframe = getNewIframe( id ),
+ $iframe = $( iframe );
+
+ for ( key in data ) {
+ if ( !fieldsAllowed[ key ] ) {
+ delete data[ key ];
+ }
+ }
+
+ data = $.extend( {}, this.defaults.parameters, { action: 'upload' }, data );
+ $form.addClass( 'mw-api-upload-form' );
+
+ $form.css( 'display', 'none' )
+ .attr( {
+ action: this.defaults.ajax.url,
+ method: 'POST',
+ target: id,
+ enctype: 'multipart/form-data'
+ } );
+
+ $iframe.one( 'load', function () {
+ $iframe.one( 'load', function () {
+ var result = processIframeResult( iframe );
+ deferred.notify( 1 );
+
+ if ( !result ) {
+ deferred.reject( 'ok-but-empty', 'No response from API on upload attempt.' );
+ } else if ( result.error ) {
+ if ( result.error.code === 'badtoken' ) {
+ api.badToken( 'edit' );
+ }
+
+ deferred.reject( result.error.code, result );
+ } else if ( result.upload && result.upload.warnings ) {
+ deferred.reject( getFirstKey( result.upload.warnings ), result );
+ } else {
+ deferred.resolve( result );
+ }
+ } );
+ tokenPromise.done( function () {
+ $form.submit();
+ } );
+ } );
+
+ $iframe.error( function ( error ) {
+ deferred.reject( 'http', error );
+ } );
+
+ $iframe.prop( 'src', 'about:blank' ).hide();
+
+ file.name = 'file';
+
+ $.each( data, function ( key, val ) {
+ $form.append( getHiddenInput( key, val ) );
+ } );
+
+ if ( !data.filename && !data.stash ) {
+ throw new Error( 'Filename not included in file data.' );
+ }
+
+ if ( this.needToken() ) {
+ this.getEditToken().then( function ( token ) {
+ $form.append( getHiddenInput( 'token', token ) );
+ tokenPromise.resolve();
+ }, tokenPromise.reject );
+ } else {
+ tokenPromise.resolve();
+ }
+
+ $( 'body' ).append( $form, $iframe );
+
+ deferred.always( function () {
+ $form.remove();
+ $iframe.remove();
+ } );
+
+ return deferred.promise();
+ },
+
+ /**
+ * Uploads a file using the FormData API.
+ *
+ * @private
+ * @param {File} file
+ * @param {Object} data Other upload options, see action=upload API docs for more
+ * @return {jQuery.Promise}
+ */
+ uploadWithFormData: function ( file, data ) {
+ var key,
+ deferred = $.Deferred();
+
+ for ( key in data ) {
+ if ( !fieldsAllowed[ key ] ) {
+ delete data[ key ];
+ }
+ }
+
+ data = $.extend( {}, this.defaults.parameters, { action: 'upload' }, data );
+ data.file = file;
+
+ if ( !data.filename && !data.stash ) {
+ throw new Error( 'Filename not included in file data.' );
+ }
+
+ // Use this.postWithEditToken() or this.post()
+ this[ this.needToken() ? 'postWithEditToken' : 'post' ]( data, {
+ // Use FormData (if we got here, we know that it's available)
+ contentType: 'multipart/form-data',
+ // Provide upload progress notifications
+ xhr: function () {
+ var xhr = $.ajaxSettings.xhr();
+ if ( xhr.upload ) {
+ // need to bind this event before we open the connection (see note at
+ // https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Using_XMLHttpRequest#Monitoring_progress)
+ xhr.upload.addEventListener( 'progress', function ( ev ) {
+ if ( ev.lengthComputable ) {
+ deferred.notify( ev.loaded / ev.total );
+ }
+ } );
+ }
+ return xhr;
+ }
+ } )
+ .done( function ( result ) {
+ deferred.notify( 1 );
+ if ( result.upload && result.upload.warnings ) {
+ deferred.reject( getFirstKey( result.upload.warnings ), result );
+ } else {
+ deferred.resolve( result );
+ }
+ } )
+ .fail( function ( errorCode, result ) {
+ deferred.notify( 1 );
+ deferred.reject( errorCode, result );
+ } );
+
+ return deferred.promise();
+ },
+
+ /**
+ * Upload a file to the stash.
+ *
+ * This function will return a promise, which when resolved, will pass back a function
+ * to finish the stash upload. You can call that function with an argument containing
+ * more, or conflicting, data to pass to the server. For example:
+ *
+ * // upload a file to the stash with a placeholder filename
+ * api.uploadToStash( file, { filename: 'testing.png' } ).done( function ( finish ) {
+ * // finish is now the function we can use to finalize the upload
+ * // pass it a new filename from user input to override the initial value
+ * finish( { filename: getFilenameFromUser() } ).done( function ( data ) {
+ * // the upload is complete, data holds the API response
+ * } );
+ * } );
+ *
+ * @param {File|HTMLInputElement} file
+ * @param {Object} [data]
+ * @return {jQuery.Promise}
+ * @return {Function} return.finishStashUpload Call this function to finish the upload.
+ * @return {Object} return.finishStashUpload.data Additional data for the upload.
+ * @return {jQuery.Promise} return.finishStashUpload.return API promise for the final upload
+ * @return {Object} return.finishStashUpload.return.data API return value for the final upload
+ */
+ uploadToStash: function ( file, data ) {
+ var filekey,
+ api = this;
+
+ if ( !data.filename ) {
+ throw new Error( 'Filename not included in file data.' );
+ }
+
+ function finishUpload( moreData ) {
+ data = $.extend( data, moreData );
+ data.filekey = filekey;
+ data.action = 'upload';
+ data.format = 'json';
+
+ if ( !data.filename ) {
+ throw new Error( 'Filename not included in file data.' );
+ }
+
+ return api.postWithEditToken( data ).then( function ( result ) {
+ if ( result.upload && result.upload.warnings ) {
+ return $.Deferred().reject( getFirstKey( result.upload.warnings ), result ).promise();
+ }
+ return result;
+ } );
+ }
+
+ return this.upload( file, { stash: true, filename: data.filename } ).then(
+ function ( result ) {
+ filekey = result.upload.filekey;
+ return finishUpload;
+ },
+ function ( errorCode, result ) {
+ if ( result && result.upload && result.upload.filekey ) {
+ // Ignore any warnings if 'filekey' was returned, that's all we care about
+ filekey = result.upload.filekey;
+ return $.Deferred().resolve( finishUpload );
+ }
+ return $.Deferred().reject( errorCode, result );
+ }
+ );
+ },
+
+ needToken: function () {
+ return true;
+ }
+ } );
+
+ /**
+ * @class mw.Api
+ * @mixins mw.Api.plugin.upload
+ */
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.api/mediawiki.api.watch.js b/resources/src/mediawiki.api/mediawiki.api.watch.js
index 40ba136d..a2ff1292 100644
--- a/resources/src/mediawiki.api/mediawiki.api.watch.js
+++ b/resources/src/mediawiki.api/mediawiki.api.watch.js
@@ -37,7 +37,7 @@
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];
+ return $.isArray( pages ) ? data.watch : data.watch[ 0 ];
} )
.promise( { abort: apiPromise.abort } );
}
diff --git a/resources/src/mediawiki.language/languages/bs.js b/resources/src/mediawiki.language/languages/bs.js
index b56e4b29..cb9e19ed 100644
--- a/resources/src/mediawiki.language/languages/bs.js
+++ b/resources/src/mediawiki.language/languages/bs.js
@@ -4,8 +4,8 @@
mediaWiki.language.convertGrammar = function ( word, form ) {
var grammarForms = mediaWiki.language.getData( 'bs', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
switch ( form ) {
case 'instrumental': // instrumental
diff --git a/resources/src/mediawiki.language/languages/dsb.js b/resources/src/mediawiki.language/languages/dsb.js
index 69c36cc0..dc4447ab 100644
--- a/resources/src/mediawiki.language/languages/dsb.js
+++ b/resources/src/mediawiki.language/languages/dsb.js
@@ -4,8 +4,8 @@
mediaWiki.language.convertGrammar = function ( word, form ) {
var grammarForms = mediaWiki.language.getData( 'dsb', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
switch ( form ) {
case 'instrumental': // instrumental
diff --git a/resources/src/mediawiki.language/languages/fi.js b/resources/src/mediawiki.language/languages/fi.js
index d9c2b06d..2bbfc6b8 100644
--- a/resources/src/mediawiki.language/languages/fi.js
+++ b/resources/src/mediawiki.language/languages/fi.js
@@ -7,8 +7,8 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
var grammarForms, aou, origWord;
grammarForms = mediaWiki.language.getData( 'fi', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
// vowel harmony flag
diff --git a/resources/src/mediawiki.language/languages/ga.js b/resources/src/mediawiki.language/languages/ga.js
index fb4e9396..a4c911a3 100644
--- a/resources/src/mediawiki.language/languages/ga.js
+++ b/resources/src/mediawiki.language/languages/ga.js
@@ -5,8 +5,8 @@
mediaWiki.language.convertGrammar = function ( word, form ) {
/*jshint onecase:true */
var grammarForms = mediaWiki.language.getData( 'ga', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
switch ( form ) {
case 'ainmlae':
diff --git a/resources/src/mediawiki.language/languages/he.js b/resources/src/mediawiki.language/languages/he.js
index d1eba43b..945f02fe 100644
--- a/resources/src/mediawiki.language/languages/he.js
+++ b/resources/src/mediawiki.language/languages/he.js
@@ -4,8 +4,8 @@
mediaWiki.language.convertGrammar = function ( word, form ) {
var grammarForms = mediaWiki.language.getData( 'he', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
switch ( form ) {
case 'prefixed':
diff --git a/resources/src/mediawiki.language/languages/hsb.js b/resources/src/mediawiki.language/languages/hsb.js
index 2c0abd3d..8e9b1296 100644
--- a/resources/src/mediawiki.language/languages/hsb.js
+++ b/resources/src/mediawiki.language/languages/hsb.js
@@ -4,8 +4,8 @@
mediaWiki.language.convertGrammar = function ( word, form ) {
var grammarForms = mediaWiki.language.getData( 'hsb', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
switch ( form ) {
case 'instrumental': // instrumental
diff --git a/resources/src/mediawiki.language/languages/hu.js b/resources/src/mediawiki.language/languages/hu.js
index d72a1c05..4f8f74df 100644
--- a/resources/src/mediawiki.language/languages/hu.js
+++ b/resources/src/mediawiki.language/languages/hu.js
@@ -5,8 +5,8 @@
mediaWiki.language.convertGrammar = function ( word, form ) {
var grammarForms = mediaWiki.language.getData( 'hu', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
switch ( form ) {
case 'rol':
diff --git a/resources/src/mediawiki.language/languages/hy.js b/resources/src/mediawiki.language/languages/hy.js
index c4a1cf73..935d466d 100644
--- a/resources/src/mediawiki.language/languages/hy.js
+++ b/resources/src/mediawiki.language/languages/hy.js
@@ -5,8 +5,8 @@
mediaWiki.language.convertGrammar = function ( word, form ) {
/*jshint onecase:true */
var grammarForms = mediaWiki.language.getData( 'hy', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
// These rules are not perfect, but they are currently only used for site names so it doesn't
diff --git a/resources/src/mediawiki.language/languages/la.js b/resources/src/mediawiki.language/languages/la.js
index 52e8dd44..29e04a67 100644
--- a/resources/src/mediawiki.language/languages/la.js
+++ b/resources/src/mediawiki.language/languages/la.js
@@ -5,8 +5,8 @@
mediaWiki.language.convertGrammar = function ( word, form ) {
var grammarForms = mediaWiki.language.getData( 'la', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
switch ( form ) {
case 'genitive':
@@ -30,7 +30,7 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
word = word.replace( /nuntii$/i, 'nuntios' );// 2nd declension plural (partly)
word = word.replace( /tio$/i, 'tionem' ); // 3rd declension singular (partly)
word = word.replace( /ns$/i, 'ntem' );
- word = word.replace( /as$/i, 'atem');
+ word = word.replace( /as$/i, 'atem' );
word = word.replace( /es$/i, 'em' ); // 5th declension singular
break;
case 'ablative':
@@ -42,7 +42,7 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
word = word.replace( /nuntii$/i, 'nuntiis' ); // 2nd declension plural (partly)
word = word.replace( /tio$/i, 'tione' ); // 3rd declension singular (partly)
word = word.replace( /ns$/i, 'nte' );
- word = word.replace( /as$/i, 'ate');
+ word = word.replace( /as$/i, 'ate' );
word = word.replace( /es$/i, 'e' ); // 5th declension singular
break;
}
diff --git a/resources/src/mediawiki.language/languages/os.js b/resources/src/mediawiki.language/languages/os.js
index 554e99d4..3e0f279d 100644
--- a/resources/src/mediawiki.language/languages/os.js
+++ b/resources/src/mediawiki.language/languages/os.js
@@ -14,8 +14,8 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
// Variable for ending
ending = '';
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
// Checking if the $word is in plural form
if ( word.match( /тæ$/i ) ) {
diff --git a/resources/src/mediawiki.language/languages/ru.js b/resources/src/mediawiki.language/languages/ru.js
index 2077b6be..ee1d6ef2 100644
--- a/resources/src/mediawiki.language/languages/ru.js
+++ b/resources/src/mediawiki.language/languages/ru.js
@@ -10,8 +10,8 @@ mediaWiki.language.convertGrammar = function ( word, form ) {
'use strict';
var grammarForms = mediaWiki.language.getData( 'ru', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
switch ( form ) {
case 'genitive': // родительный падеж
diff --git a/resources/src/mediawiki.language/languages/sl.js b/resources/src/mediawiki.language/languages/sl.js
index d20d0b34..3d8bdfde 100644
--- a/resources/src/mediawiki.language/languages/sl.js
+++ b/resources/src/mediawiki.language/languages/sl.js
@@ -4,8 +4,8 @@
mediaWiki.language.convertGrammar = function ( word, form ) {
var grammarForms = mediaWiki.language.getData( 'sl', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
switch ( form ) {
case 'mestnik': // locative
diff --git a/resources/src/mediawiki.language/languages/uk.js b/resources/src/mediawiki.language/languages/uk.js
index 550a388c..a22874b3 100644
--- a/resources/src/mediawiki.language/languages/uk.js
+++ b/resources/src/mediawiki.language/languages/uk.js
@@ -4,31 +4,31 @@
mediaWiki.language.convertGrammar = function ( word, form ) {
var grammarForms = mediaWiki.language.getData( 'uk', 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word];
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ];
}
switch ( form ) {
case 'genitive': // родовий відмінок
if ( word.slice( -4 ) !== 'вікі' && word.slice( -4 ) !== 'Вікі' ) {
if ( word.slice( -1 ) === 'ь' ) {
- word = word.slice(0, -1 ) + 'я';
+ word = word.slice( 0, -1 ) + 'я';
} else if ( word.slice( -2 ) === 'ія' ) {
- word = word.slice(0, -2 ) + 'ії';
+ word = word.slice( 0, -2 ) + 'ії';
} else if ( word.slice( -2 ) === 'ка' ) {
- word = word.slice(0, -2 ) + 'ки';
+ word = word.slice( 0, -2 ) + 'ки';
} else if ( word.slice( -2 ) === 'ти' ) {
- word = word.slice(0, -2 ) + 'тей';
+ word = word.slice( 0, -2 ) + 'тей';
} else if ( word.slice( -2 ) === 'ды' ) {
- word = word.slice(0, -2 ) + 'дов';
+ word = word.slice( 0, -2 ) + 'дов';
} else if ( word.slice( -3 ) === 'ник' ) {
- word = word.slice(0, -3 ) + 'ника';
+ word = word.slice( 0, -3 ) + 'ника';
}
}
break;
case 'accusative': // знахідний відмінок
if ( word.slice( -4 ) !== 'вікі' && word.slice( -4 ) !== 'Вікі' ) {
if ( word.slice( -2 ) === 'ія' ) {
- word = word.slice(0, -2 ) + 'ію';
+ word = word.slice( 0, -2 ) + 'ію';
}
}
break;
diff --git a/resources/src/mediawiki.language/mediawiki.cldr.js b/resources/src/mediawiki.language/mediawiki.cldr.js
index f6fb8f10..ca4b6fbe 100644
--- a/resources/src/mediawiki.language/mediawiki.cldr.js
+++ b/resources/src/mediawiki.language/mediawiki.cldr.js
@@ -21,7 +21,7 @@
getPluralForm: function ( number, pluralRules ) {
var i;
for ( i = 0; i < pluralRules.length; i++ ) {
- if ( mw.libs.pluralRuleParser( pluralRules[i], number ) ) {
+ if ( mw.libs.pluralRuleParser( pluralRules[ i ], number ) ) {
break;
}
}
diff --git a/resources/src/mediawiki.language/mediawiki.language.init.js b/resources/src/mediawiki.language/mediawiki.language.init.js
index b3765c85..808f6e5e 100644
--- a/resources/src/mediawiki.language/mediawiki.language.init.js
+++ b/resources/src/mediawiki.language/mediawiki.language.init.js
@@ -55,8 +55,8 @@
getData: function ( langCode, dataKey ) {
var langData = mw.language.data;
langCode = langCode.toLowerCase();
- if ( langData && langData[langCode] instanceof mw.Map ) {
- return langData[langCode].get( dataKey );
+ if ( langData && langData[ langCode ] instanceof mw.Map ) {
+ return langData[ langCode ].get( dataKey );
}
return undefined;
},
@@ -73,10 +73,10 @@
setData: function ( langCode, dataKey, value ) {
var langData = mw.language.data;
langCode = langCode.toLowerCase();
- if ( !( langData[langCode] instanceof mw.Map ) ) {
- langData[langCode] = new mw.Map();
+ if ( !( langData[ langCode ] instanceof mw.Map ) ) {
+ langData[ langCode ] = new mw.Map();
}
- langData[langCode].set( dataKey, value );
+ langData[ langCode ].set( dataKey, value );
}
};
diff --git a/resources/src/mediawiki.language/mediawiki.language.js b/resources/src/mediawiki.language/mediawiki.language.js
index 78e39191..0d324ed3 100644
--- a/resources/src/mediawiki.language/mediawiki.language.js
+++ b/resources/src/mediawiki.language/mediawiki.language.js
@@ -29,8 +29,8 @@ $.extend( mw.language, {
return mw.language.convertPlural( parseInt( count, 10 ), template.parameters );
}
// Could not process plural return first form or nothing
- if ( template.parameters[0] ) {
- return template.parameters[0];
+ if ( template.parameters[ 0 ] ) {
+ return template.parameters[ 0 ];
}
return '';
},
@@ -47,8 +47,8 @@ $.extend( mw.language, {
var pluralRules,
pluralFormIndex = 0;
- if ( explicitPluralForms && explicitPluralForms[count] ) {
- return explicitPluralForms[count];
+ if ( explicitPluralForms && explicitPluralForms[ count ] ) {
+ return explicitPluralForms[ count ];
}
if ( !forms || forms.length === 0 ) {
@@ -58,11 +58,11 @@ $.extend( mw.language, {
pluralRules = mw.language.getData( mw.config.get( 'wgUserLanguage' ), 'pluralRules' );
if ( !pluralRules ) {
// default fallback.
- return ( count === 1 ) ? forms[0] : forms[1];
+ return ( count === 1 ) ? forms[ 0 ] : forms[ 1 ];
}
pluralFormIndex = mw.cldr.getPluralForm( count, pluralRules );
pluralFormIndex = Math.min( pluralFormIndex, forms.length - 1 );
- return forms[pluralFormIndex];
+ return forms[ pluralFormIndex ];
},
/**
@@ -90,7 +90,7 @@ $.extend( mw.language, {
*
* @param {string} gender 'male', 'female', or anything else for neutral.
* @param {Array} forms List of gender forms
- * @return string
+ * @return {string}
*/
gender: function ( gender, forms ) {
if ( !forms || forms.length === 0 ) {
@@ -98,12 +98,12 @@ $.extend( mw.language, {
}
forms = mw.language.preConvertPlural( forms, 2 );
if ( gender === 'male' ) {
- return forms[0];
+ return forms[ 0 ];
}
if ( gender === 'female' ) {
- return forms[1];
+ return forms[ 1 ];
}
- return ( forms.length === 3 ) ? forms[2] : forms[0];
+ return ( forms.length === 3 ) ? forms[ 2 ] : forms[ 0 ];
},
/**
@@ -119,8 +119,8 @@ $.extend( mw.language, {
*/
convertGrammar: function ( word, form ) {
var grammarForms = mw.language.getData( mw.config.get( 'wgUserLanguage' ), 'grammarForms' );
- if ( grammarForms && grammarForms[form] ) {
- return grammarForms[form][word] || word;
+ if ( grammarForms && grammarForms[ form ] ) {
+ return grammarForms[ form ][ word ] || word;
}
return word;
},
@@ -138,7 +138,7 @@ $.extend( mw.language, {
i = 0;
for ( ; i < list.length; i++ ) {
- text += list[i];
+ text += list[ i ];
if ( list.length - 2 === i ) {
text += mw.msg( 'and' ) + mw.msg( 'word-separator' );
} else if ( list.length - 1 !== i ) {
diff --git a/resources/src/mediawiki.language/mediawiki.language.numbers.js b/resources/src/mediawiki.language/mediawiki.language.numbers.js
index 3c13055b..268985f8 100644
--- a/resources/src/mediawiki.language/mediawiki.language.numbers.js
+++ b/resources/src/mediawiki.language/mediawiki.language.numbers.js
@@ -7,6 +7,26 @@
*/
/**
+ * Replicate a string 'n' times.
+ *
+ * @private
+ * @param {string} str The string to replicate
+ * @param {number} num Number of times to replicate the string
+ * @return {string}
+ */
+ function replicate( str, num ) {
+ if ( num <= 0 || !str ) {
+ return '';
+ }
+
+ var buf = [];
+ while ( num-- ) {
+ buf.push( str );
+ }
+ return buf.join( '' );
+ }
+
+ /**
* Pad a string to guarantee that it is at least `size` length by
* filling with the character `ch` at either the start or end of the
* string. Pads at the start, by default.
@@ -34,26 +54,6 @@
}
/**
- * Replicate a string 'n' times.
- *
- * @private
- * @param {string} str The string to replicate
- * @param {number} num Number of times to replicate the string
- * @return {string}
- */
- function replicate( str, num ) {
- if ( num <= 0 || !str ) {
- return '';
- }
-
- var buf = [];
- while ( num-- ) {
- buf.push( str );
- }
- return buf.join( '' );
- }
-
- /**
* Apply numeric pattern to absolute value using options. Gives no
* consideration to local customs.
*
@@ -74,7 +74,7 @@
decimal: '.'
};
- if ( isNaN( value) ) {
+ if ( isNaN( value ) ) {
return value;
}
@@ -85,62 +85,62 @@
off,
remainder,
patternParts = pattern.split( '.' ),
- maxPlaces = ( patternParts[1] || [] ).length,
+ maxPlaces = ( patternParts[ 1 ] || [] ).length,
valueParts = String( Math.abs( value ) ).split( '.' ),
- fractional = valueParts[1] || '',
+ fractional = valueParts[ 1 ] || '',
groupSize = 0,
groupSize2 = 0,
pieces = [];
- if ( patternParts[1] ) {
+ if ( patternParts[ 1 ] ) {
// Pad fractional with trailing zeros
- padLength = ( patternParts[1] && patternParts[1].lastIndexOf( '0' ) + 1 );
+ padLength = ( patternParts[ 1 ] && patternParts[ 1 ].lastIndexOf( '0' ) + 1 );
if ( padLength > fractional.length ) {
- valueParts[1] = pad( fractional, padLength, '0', true );
+ valueParts[ 1 ] = pad( fractional, padLength, '0', true );
}
// Truncate fractional
if ( maxPlaces < fractional.length ) {
- valueParts[1] = fractional.slice( 0, maxPlaces );
+ valueParts[ 1 ] = fractional.slice( 0, maxPlaces );
}
} else {
- if ( valueParts[1] ) {
+ if ( valueParts[ 1 ] ) {
valueParts.pop();
}
}
// Pad whole with leading zeros
- patternDigits = patternParts[0].replace( ',', '' );
+ patternDigits = patternParts[ 0 ].replace( ',', '' );
padLength = patternDigits.indexOf( '0' );
if ( padLength !== -1 ) {
padLength = patternDigits.length - padLength;
- if ( padLength > valueParts[0].length ) {
- valueParts[0] = pad( valueParts[0], padLength );
+ if ( padLength > valueParts[ 0 ].length ) {
+ valueParts[ 0 ] = pad( valueParts[ 0 ], padLength );
}
// Truncate whole
if ( patternDigits.indexOf( '#' ) === -1 ) {
- valueParts[0] = valueParts[0].slice( valueParts[0].length - padLength );
+ valueParts[ 0 ] = valueParts[ 0 ].slice( valueParts[ 0 ].length - padLength );
}
}
// Add group separators
- index = patternParts[0].lastIndexOf( ',' );
+ index = patternParts[ 0 ].lastIndexOf( ',' );
if ( index !== -1 ) {
- groupSize = patternParts[0].length - index - 1;
- remainder = patternParts[0].slice( 0, index );
+ groupSize = patternParts[ 0 ].length - index - 1;
+ remainder = patternParts[ 0 ].slice( 0, index );
index = remainder.lastIndexOf( ',' );
if ( index !== -1 ) {
groupSize2 = remainder.length - index - 1;
}
}
- for ( whole = valueParts[0]; whole; ) {
+ for ( whole = valueParts[ 0 ]; whole; ) {
off = groupSize ? whole.length - groupSize : 0;
pieces.push( ( off > 0 ) ? whole.slice( off ) : whole );
whole = ( off > 0 ) ? whole.slice( 0, off ) : '';
@@ -150,7 +150,7 @@
groupSize2 = null;
}
}
- valueParts[0] = pieces.reverse().join( options.group );
+ valueParts[ 0 ] = pieces.reverse().join( options.group );
return valueParts.join( options.decimal );
}
@@ -198,17 +198,18 @@
convertedNumber = '';
for ( i = 0; i < numberString.length; i++ ) {
- if ( transformTable[ numberString[i] ] ) {
- convertedNumber += transformTable[numberString[i]];
+ if ( transformTable[ numberString[ i ] ] ) {
+ convertedNumber += transformTable[ numberString[ i ] ];
} else {
- convertedNumber += numberString[i];
+ convertedNumber += numberString[ i ];
}
}
return integer ? parseInt( convertedNumber, 10 ) : convertedNumber;
},
/**
- * Get the digit transform table for current UI language.
+ * Get the digit transform table for current UI language.
+ *
* @return {Object|Array}
*/
getDigitTransformTable: function () {
@@ -217,7 +218,8 @@
},
/**
- * Get the separator transform table for current UI language.
+ * Get the separator transform table for current UI language.
+ *
* @return {Object|Array}
*/
getSeparatorTransformTable: function () {
@@ -238,20 +240,20 @@
commafy: function ( value, pattern ) {
var numberPattern,
transformTable = mw.language.getSeparatorTransformTable(),
- group = transformTable[','] || ',',
+ group = transformTable[ ',' ] || ',',
numberPatternRE = /[#0,]*[#0](?:\.0*#*)?/, // not precise, but good enough
- decimal = transformTable['.'] || '.',
+ decimal = transformTable[ '.' ] || '.',
patternList = pattern.split( ';' ),
- positivePattern = patternList[0];
+ positivePattern = patternList[ 0 ];
- pattern = patternList[ ( value < 0 ) ? 1 : 0] || ( '-' + positivePattern );
+ pattern = patternList[ ( value < 0 ) ? 1 : 0 ] || ( '-' + positivePattern );
numberPattern = positivePattern.match( numberPatternRE );
if ( !numberPattern ) {
throw new Error( 'unable to find a number expression in pattern: ' + pattern );
}
- return pattern.replace( numberPatternRE, commafyNumber( value, numberPattern[0], {
+ return pattern.replace( numberPatternRE, commafyNumber( value, numberPattern[ 0 ], {
decimal: decimal,
group: group
} ) );
diff --git a/resources/src/mediawiki.language/specialcharacters.json b/resources/src/mediawiki.language/specialcharacters.json
index bab92a1b..d4446ab8 100644
--- a/resources/src/mediawiki.language/specialcharacters.json
+++ b/resources/src/mediawiki.language/specialcharacters.json
@@ -1 +1,445 @@
-{"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
+{
+ "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": [
+ "ঀ", "অ", "আ", "ই", "ঈ", "উ", "ঊ", "ঋ", "ঌ", "এ", "ঐ", "ও", "ঔ", "া", "ি", "ী", "ু", "ূ", "ৃ", "ে", "ৈ", "ো", "ৌ", "্য", "্র", "ক", "খ", "গ", "ঘ", "ঙ", "চ", "ছ", "জ", "ঝ", "ঞ", "ট", "ঠ", "ড", "ঢ", "ণ", "ত", "থ", "দ", "ধ", "ন", "প", "ফ", "ব", "ভ", "ম", "য", "র", "ল", "শ", "ষ", "স", "হ", "ড়", "ঢ়", "য়", "ৎ", "ং", "ঃ", "ঁ", "্", "৷", "॥", "১", "২", "৩", "৪", "৫", "৬", "৭", "৮", "৯", "০", "ঽ", "ৗ", "়", "ৰ", "ৱ", "৲", "৻", "৳", "৴", "৵", "৶", "৷", "৸", "৹", "৺", "ৠ", "ৡ", "ৄ", "ৢ", "ৣ", "‘", "’", "“", "”",
+ [
+ "zws",
+ "​"
+ ],
+ [
+ "zwnj",
+ "‌"
+ ],
+ [
+ "zwj",
+ "‍"
+ ]
+ ],
+ "tamil": [
+ "௦", "௧", "௨", "௩", "௪", "௫", "௬", "௭", "௮", "௯", "௰", "௱", "௲", "௳", "௴", "௵", "௶", "௷", "௸", "௹", "௺", "ௐ"
+ ],
+ "telugu": [
+ "ఁ", "ం", "ః", "అ", "ఆ", "ఇ", "ఈ", "ఉ", "ఊ", "ఋ", "ౠ", "ఌ", "ౡ", "ఎ", "ఏ", "ఐ", "ఒ", "ఓ", "ఔ", "క", "ఖ", "గ", "ఘ", "ఙ", "చ", "ఛ", "జ", "ఝ", "ఞ", "ట", "ఠ", "డ", "ఢ", "ణ", "త", "థ", "ద", "ధ", "న", "ప", "ఫ", "బ", "భ", "మ", "య", "ర", "ఱ", "ల", "ళ", "వ", "శ", "ష", "స", "హ", "ా", "ి", "ీ", "ు", "ూ", "ృ", "ౄ", "ె", "ే", "ై", "ొ", "ో", "ౌ", "్", "ౢ", "ౣ", "ౘ", "ౙ", "౦", "౧", "౨", "౩", "౪", "౫", "౬", "౭", "౮", "౯", "ఽ", "౸", "౹", "౺", "౻", "౼", "౽", "౾", "౿"
+ ],
+ "sinhala": [
+ "අ", "ආ", "ඇ", "ඈ", "ඉ", "ඊ", "උ", "ඌ", "ඍ", "ඎ", "ඏ", "ඐ", "එ", "ඒ", "ඓ", "ඔ", "ඕ", "ඖ", "ක", "ඛ", "ග", "ඝ", "ඞ", "ඟ", "ච", "ඡ", "ජ", "ඣ", "ඤ", "ඥ", "ඦ", "ට", "ඨ", "ඩ", "ඪ", "ණ", "ඬ", "ත", "ථ", "ද", "ධ", "න", "ඳ", "ප", "ඵ", "බ", "භ", "ම", "ඹ", "ය", "ර", "ල", "ව", "ශ", "ෂ", "ස", "හ", "ළ", "ෆ",
+ [
+ "◌ා",
+ "ා"
+ ],
+ [
+ "◌ැ",
+ "ැ"
+ ],
+ [
+ "◌ෑ",
+ "ෑ"
+ ],
+ [
+ "◌ි",
+ "ි"
+ ],
+ [
+ "◌ී",
+ "ී"
+ ],
+ [
+ "◌ු",
+ "ු"
+ ],
+ [
+ "◌ූ",
+ "ූ"
+ ],
+ [
+ "◌ෘ",
+ "ෘ"
+ ],
+ [
+ "◌ෲ",
+ "ෲ"
+ ],
+ [
+ "◌ෟ",
+ "ෟ"
+ ],
+ [
+ "◌ෳ",
+ "ෳ"
+ ],
+ [
+ "◌ෙ",
+ "ෙ"
+ ],
+ [
+ "◌ේ",
+ "ේ"
+ ],
+ [
+ "◌ො",
+ "ො"
+ ],
+ [
+ "◌ෝ",
+ "ෝ"
+ ],
+ [
+ "◌ෞ",
+ "ෞ"
+ ],
+ [
+ "◌්",
+ "්"
+ ]
+ ],
+ "devanagari": [
+ "ऀ", "ँ", "ं", "ः", "ऄ", "अ", "आ", "इ", "ई", "उ", "ऊ", "ऋ", "ऌ", "ऍ", "ऎ", "ए", "ऐ", "ऑ", "ऒ", "ओ", "औ", "क", "ख", "ग", "घ", "ङ", "च", "छ", "ज", "झ", "ञ", "ट", "ठ", "ड", "ढ", "ण", "त", "थ", "द", "ध", "न", "ऩ", "प", "फ", "ब", "भ", "म", "य", "र", "ऱ", "ल", "ळ", "ऴ", "व", "श", "ष", "स", "ह", "ऺ", "ऻ", "़", "ऽ", "ा", "ि", "ी", "ु", "ू", "ृ", "ॄ", "ॅ", "ॆ", "े", "ै", "ॉ", "ॊ", "ो", "ौ", "्", "ॎ", "ॏ", "ॐ", "॑", "॒", "॓", "॔", "ॕ", "ॖ", "ॗ", "क़", "ख़", "ग़", "ज़", "ड़", "ढ़", "फ़", "य़", "ॠ", "ॡ", "ॢ", "ॣ", "।", "॥", "०", "१", "२", "३", "४", "५", "६", "७", "८", "९", "॰", "ॱ", "ॲ", "ॳ", "ॴ", "ॵ", "ॶ", "ॷ", "ॹ", "ॺ", "ॻ", "ॼ", "ॽ", "ॾ", "ॿ"
+ ],
+ "gujarati": [
+ "ૐ", "ઁ", "ં", "ઃ", "અ", "આ", "ઇ", "ઈ", "ઉ", "ઊ", "એ", "ઐ", "ઓ", "ઔ", "અં", "ઋ", "ઍ", "ઑ", "ઌ", "ૠ", "ૡ", "ક", "ખ", "ગ", "ઘ", "ઙ", "ચ", "છ", "જ", "ઝ", "ઞ", "ટ", "ઠ", "ડ", "ઢ", "ણ", "ત", "થ", "દ", "ધ", "ન", "પ", "ફ", "બ", "ભ", "મ", "ય", "ર", "લ", "ળ", "વ", "શ", "ષ", "સ", "હ", "ક્ષ", "જ્ઞ", "ઽ", "ા", "િ", "ી", "ી", "ુ", "ૂ", "ૃ", "ૄ", "ૅ", "ે", "ૈ", "ૉ", "ો", "ૌ", "ૢ", "ૣ", "્", "૦", "૧", "૨", "૩", "૪", "૫", "૬", "૭", "૮", "૯", "૱"
+ ],
+ "thai": [
+ "ก", "ข", "ฃ", "ค", "ฅ", "ฆ", "ง", "จ", "ฉ", "ช", "ซ", "ฌ", "ญ", "ฎ", "ฏ", "ฐ", "ฑ", "ฒ", "ณ", "ด", "ต", "ถ", "ท", "ธ", "น", "บ", "ป", "ผ", "ฝ", "พ", "ฟ", "ภ", "ม", "ย", "ร", "ฤ", "ล", "ฦ", "ว", "ศ", "ษ", "ส", "ห", "ฬ", "อ", "ฮ", "ะ", "ั", "า", "ๅ", "ำ", "ิ", "ี", "ึ", "ื", "ุ", "ู", "เ", "แ", "โ", "ใ", "ไ", "็", "่", "้", "๊", "๋", "์", "ํ", "ฺ", "๎", "๐", "๑", "๒", "๓", "๔", "๕", "๖", "๗", "๘", "๙", "฿", "ๆ", "ฯ", "๚", "๏", "๛"
+ ],
+ "lao": [
+ "ກ", "ຂ", "ຄ", "ງ", "ຈ", "ສ", "ຊ", "ຍ", "ດ", "ຕ", "ຖ", "ທ", "ນ", "ບ", "ປ", "ຜ", "ຝ", "ພ", "ຟ", "ມ", "ຢ", "ລ", "ວ", "ຫ", "ອ", "ຮ", "ຣ", "ໜ", "ໝ", "ຼ", "ຽ", "ະ", "ັ", "າ", "ຳ", "ິ", "ີ", "ຶ", "ື", "ຸ", "ູ", "ົ", "ເ", "ແ", "ໂ", "ໃ", "ໄ", "່", "້", "໊", "໋", "໌", "ໍ", "໐", "໑", "໒", "໓", "໔", "໕", "໖", "໗", "໘", "໙", "₭", "ໆ", "ຯ"
+ ],
+ "khmer": [
+ "ក", "ខ", "គ", "ឃ", "ង", "ច", "ឆ", "ជ", "ឈ", "ញ", "ដ", "ឋ", "ឌ", "ឍ", "ណ", "ត", "ថ", "ទ", "ធ", "ន", "ប", "ផ", "ព", "ភ", "ម", "យ", "រ", "ល", "វ", "ស", "ហ", "ឡ", "អ", "ឣ", "ឤ", "ឥ", "ឦ", "ឧ", "ឨ", "ឩ", "ឪ", "ឫ", "ឬ", "ឭ", "ឮ", "ឯ", "ឰ", "ឱ", "ឲ", "ឳ", "្", "឴", "឵", "ា", "ិ", "ី", "ឹ", "ឺ", "ុ", "ូ", "ួ", "ើ", "ឿ", "ៀ", "េ", "ែ", "ៃ", "ោ", "ៅ", "ំ", "ះ", "ៈ", "៉", "៊", "់", "៌", "៍", "៎", "៏", "័", "៑", "៓", "៝", "ៜ", "០", "១", "២", "៣", "៤", "៥", "៦", "៧", "៨", "៩", "៛", "។", "៕", "៖", "ៗ", "៘", "៙", "៚", "៰", "៱", "៲", "៳", "៴", "៵", "៶", "៷", "៸", "៹", "᧠", "᧡", "᧢", "᧣", "᧤", "᧥", "᧦", "᧧", "᧨", "᧩", "᧪", "᧫", "᧬", "᧭", "᧮", "᧯", "᧰", "᧱", "᧲", "᧳", "᧴", "᧵", "᧶", "᧷", "᧸", "᧹", "᧺", "᧻", "᧼", "᧽", "᧾", "᧿"
+ ]
+}
diff --git a/resources/src/mediawiki.legacy/ajax.js b/resources/src/mediawiki.legacy/ajax.js
deleted file mode 100644
index 3660c205..00000000
--- a/resources/src/mediawiki.legacy/ajax.js
+++ /dev/null
@@ -1,194 +0,0 @@
-/**
- * Remote Scripting Library
- * Copyright 2005 modernmethod, inc
- * Under the open source BSD license
- * http://www.modernmethod.com/sajax/
- */
-
-/*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;
- }
-
- var b, m,
- e = document.getElementById( 'sajax_debug' );
-
- if ( !e ) {
- e = document.createElement( 'p' );
- e.className = 'sajax_debug';
- e.id = 'sajax_debug';
-
- b = document.getElementsByTagName( 'body' )[0];
-
- if ( b.firstChild ) {
- b.insertBefore( e, b.firstChild );
- } else {
- b.appendChild( e );
- }
- }
-
- m = document.createElement( 'div' );
- m.appendChild( document.createTextNode( text ) );
-
- e.appendChild( m );
-
- 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 ) {
- try {
- 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.' );
- }
-
- 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 );
- } 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 {
- 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;
- }
-
- 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;
- }
- 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 );
-
- // 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;
- } 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 );
- }
- };
-
- debug( func_name + ' uri = ' + uri + ' / post = ' + post_data );
- x.send( post_data );
- debug( func_name + ' waiting..' );
-
- return true;
- }
-
- /**
- * @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 );
-
-}( mediaWiki ) );
diff --git a/resources/src/mediawiki.legacy/commonPrint.css b/resources/src/mediawiki.legacy/commonPrint.css
index 9a8d3918..e1b31982 100644
--- a/resources/src/mediawiki.legacy/commonPrint.css
+++ b/resources/src/mediawiki.legacy/commonPrint.css
@@ -16,7 +16,6 @@ div#jump-to-nav,
.mw-jump,
div.top,
div#column-one,
-#colophon,
.mw-editsection,
.mw-editsection-like,
.toctoggle,
@@ -29,9 +28,6 @@ li#mobileview,
li#privacy,
#footer-places,
.mw-hidden-catlinks,
-tr.mw-metadata-show-hide-extended,
-span.mw-filepage-other-resolutions,
-#filetoc,
.usermessage,
.patrollink,
.ns-0 .mw-redirectedfrom,
@@ -123,7 +119,6 @@ pre, .mw-code {
border: 1px solid #aaaaaa;
background-color: #f9f9f9;
padding: 5px;
- display: -moz-inline-block;
display: inline-block;
display: table;
/* IE7 and earlier */
@@ -286,45 +281,6 @@ img.thumbborder {
}
/**
- * Galleries (see shared.css for more info)
- */
-li.gallerybox {
- vertical-align: top;
- display: inline-block;
-}
-
-ul.gallery, li.gallerybox {
- zoom: 1;
- *display: inline;
-}
-
-ul.gallery {
- margin: 2px;
- padding: 2px;
- display: block;
-}
-
-li.gallerycaption {
- font-weight: bold;
- text-align: center;
- display: block;
- word-wrap: break-word;
-}
-
-li.gallerybox div.thumb {
- text-align: center;
- border: 1px solid #ccc;
- margin: 2px;
-}
-
-div.gallerytext {
- overflow: hidden;
- font-size: 94%;
- padding: 2px 4px;
- word-wrap: break-word;
-}
-
-/**
* Table rendering
* As on shared.css but with white background.
*/
diff --git a/resources/src/mediawiki.legacy/oldshared.css b/resources/src/mediawiki.legacy/oldshared.css
index c2bd5a73..66161ed3 100644
--- a/resources/src/mediawiki.legacy/oldshared.css
+++ b/resources/src/mediawiki.legacy/oldshared.css
@@ -168,7 +168,6 @@ img {
padding: 5px;
font-size: 95%;
text-align: center;
- display: -moz-inline-block;
display: inline-block;
display: table;
@@ -257,14 +256,6 @@ div.htmlform-tip {
color: #666;
}
-fieldset.prefsection {
- margin-top: 1em;
-}
-
-fieldset.operaprefsection {
- margin-left: 15em;
-}
-
/* emulate center */
.center {
width: 100%;
@@ -321,10 +312,6 @@ span.comment {
font-style: italic;
}
-span.changedby {
- font-size: 95%;
-}
-
.previewnote {
text-align: center;
color: #cc0000;
diff --git a/resources/src/mediawiki.legacy/protect.js b/resources/src/mediawiki.legacy/protect.js
index 3f4b263e..6226c90b 100644
--- a/resources/src/mediawiki.legacy/protect.js
+++ b/resources/src/mediawiki.legacy/protect.js
@@ -146,7 +146,7 @@ var ProtectionForm = window.ProtectionForm = {
*/
matchAttribute: function ( objects, attrName ) {
return $.map( objects, function ( object ) {
- return object[attrName];
+ return object[ attrName ];
} ).filter( function ( item, index, a ) {
return index === a.indexOf( item );
} ).length === 1;
@@ -177,6 +177,7 @@ var ProtectionForm = window.ProtectionForm = {
/**
* Find the highest protection level in any selector
+ *
* @return {number}
*/
getMaxLevel: function () {
diff --git a/resources/src/mediawiki.legacy/shared.css b/resources/src/mediawiki.legacy/shared.css
index 3657b127..961c02b2 100644
--- a/resources/src/mediawiki.legacy/shared.css
+++ b/resources/src/mediawiki.legacy/shared.css
@@ -2,6 +2,11 @@
* CSS in this file is used by *all* skins (that have any CSS at all). Be
* careful what you put in here, since what looks good in one skin may not in
* another, but don't ignore the poor pre-Monobook users either.
+ *
+ * NOTE: The images which are referenced in this file are no longer in use in
+ * essential interface components. They should NOT be embedded, because that
+ * optimizes for the uncommon case at the cost of bloating the size of render-
+ * blocking CSS common to all pages.
*/
/* GENERAL CLASSES FOR DIRECTIONALITY SUPPORT */
@@ -78,6 +83,14 @@ abbr[title],
cursor: help;
}
+@supports (text-decoration: underline dotted) {
+ abbr[title],
+ .explain[title] {
+ border-bottom: none;
+ text-decoration: underline dotted;
+ }
+}
+
/* Colored watchlist and recent changes numbers */
.mw-plusminus-pos {
color: #006400; /* dark green */
@@ -113,15 +126,11 @@ abbr[title],
font-style: italic;
}
-/* Comment and username portions of RC entries */
+/* Comment portions of RC entries */
span.comment {
font-style: italic;
}
-span.changedby {
- font-size: 95%;
-}
-
/* Math */
.texvc {
direction: ltr;
@@ -152,49 +161,6 @@ span.texhtml {
}
/**
- * File description page
- */
-
-div.mw-filepage-resolutioninfo {
- font-size: smaller;
-}
-
-/**
- * File histories
- */
-h2#filehistory {
- clear: both;
-}
-
-table.filehistory th,
-table.filehistory td {
- vertical-align: top;
-}
-
-table.filehistory th {
- text-align: left;
-}
-
-table.filehistory td.mw-imagepage-filesize,
-table.filehistory th.mw-imagepage-filesize {
- white-space: nowrap;
-}
-
-table.filehistory td.filehistory-selected {
- font-weight: bold;
-}
-
-/**
- * Add a checkered background image on hover for file
- * description pages. (bug 26470)
- */
-.filehistory a img,
-#file img:hover {
- /* @embed */
- background: white url(images/checker.png) repeat;
-}
-
-/**
* rev_deleted stuff
*/
li span.deleted,
@@ -237,73 +203,13 @@ td.mw-submit {
}
td.mw-label {
- vertical-align: top;
-}
-
-.prefsection td.mw-label {
- width: 20%;
-}
-
-.prefsection table {
- width: 100%;
-}
-
-.prefsection table.mw-htmlform-matrix {
- width: auto;
-}
-
-.mw-icon-question {
- /* 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 */
- background-image: url(images/question.png);
- /* @embed */
- background-image: -webkit-linear-gradient(transparent, transparent), url(images/question.svg);
- /* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/question.svg);
- background-repeat: no-repeat;
- background-size: 13px 13px;
- display: inline-block;
- height: 13px;
- width: 13px;
- margin-left: 4px;
-}
-
-.mw-icon-question:lang(ar),
-.mw-icon-question:lang(fa),
-.mw-icon-question:lang(ur) {
- -webkit-transform: scaleX(-1);
- -ms-transform: scaleX(-1);
- transform: scaleX(-1);
+ vertical-align: middle;
}
td.mw-submit {
white-space: nowrap;
}
-table.mw-htmlform-nolabel td.mw-label {
- width: 1px;
-}
-
-tr.mw-htmlform-vertical-label td.mw-label {
- text-align: left !important;
-}
-
-.mw-htmlform-invalid-input td.mw-input input {
- border-color: red;
-}
-
-.mw-htmlform-flatlist div.mw-htmlform-flatlist-item {
- display: inline;
- margin-right: 1em;
- white-space: nowrap;
-}
-
-.mw-htmlform-matrix td {
- padding-left: 0.5em;
- padding-right: 0.5em;
-}
-
input#wpSummary {
width: 80%;
margin-bottom: 1em;
@@ -437,11 +343,6 @@ p.mw-upload-editlicenses {
font-weight: bold;
}
-#shared-image-dup,
-#shared-image-conflict {
- font-style: italic;
-}
-
/**
* Recreating deleted page warning
* Reupload file warning
@@ -481,22 +382,6 @@ a.new {
color: #BA0000;
}
-/* feed links */
-a.feedlink {
- /* 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 */
- background-image: url(images/feed-icon.png);
- /* @embed */
- background-image: -webkit-linear-gradient(transparent, transparent), url(images/feed-icon.svg);
- /* @embed */
- background-image: linear-gradient(transparent, transparent), url(images/feed-icon.svg);
- background-position: center left;
- background-repeat: no-repeat;
- background-size: 12px 12px;
- padding-left: 16px;
-}
-
/* Plainlinks - this can be used to switch
* off special external link styling */
.plainlinks a.external {
@@ -566,7 +451,6 @@ table.wikitable > caption {
border: 1px solid;
padding: .5em 1em;
margin-bottom: 1em;
- display: -moz-inline-block;
display: inline-block;
zoom: 1;
*display: inline;
@@ -663,24 +547,6 @@ table.wikitable > caption {
background-color: #eeeeff;
}
-/* filetoc */
-ul#filetoc {
- text-align: center;
- border: 1px solid #aaaaaa;
- background-color: #f9f9f9;
- padding: 5px;
- font-size: 95%;
- margin-bottom: 0.5em;
- margin-left: 0;
- margin-right: 0;
-}
-
-#filetoc li {
- display: inline;
- list-style-type: none;
- padding-right: 2em;
-}
-
/* Classes for Exif data display */
table.mw_metadata {
font-size: 0.8em;
@@ -773,110 +639,7 @@ table.mw_metadata ul.metadata-langlist {
margin-left: 0;
}
-/* Galleries */
-/* These display attributes look nonsensical, but are needed to support IE and FF2 */
-/* Don't forget to update commonPrint.css */
-li.gallerybox {
- vertical-align: top;
- display: -moz-inline-box;
- display: inline-block;
-}
-
-ul.gallery,
-li.gallerybox {
- zoom: 1;
- *display: inline;
-}
-
-ul.gallery {
- margin: 2px;
- padding: 2px;
- display: block;
-}
-
-li.gallerycaption {
- font-weight: bold;
- text-align: center;
- display: block;
- word-wrap: break-word;
-}
-
-li.gallerybox div.thumb {
- text-align: center;
- border: 1px solid #ccc;
- background-color: #f9f9f9;
- margin: 2px;
-}
-
-li.gallerybox div.thumb img {
- display: block;
- margin: 0 auto;
-}
-
-div.gallerytext {
- overflow: hidden;
- font-size: 94%;
- padding: 2px 4px;
- word-wrap: break-word;
-}
-
-/* new gallery stuff */
-ul.mw-gallery-nolines li.gallerybox div.thumb {
- background-color: transparent;
- border: none;
-}
-
-ul.mw-gallery-nolines li.gallerybox div.gallerytext {
- text-align: center;
-}
-
-/* height constrained gallery */
-
-ul.mw-gallery-packed li.gallerybox div.thumb,
-ul.mw-gallery-packed-overlay li.gallerybox div.thumb,
-ul.mw-gallery-packed-hover li.gallerybox div.thumb {
- background-color: transparent;
- border: none;
-}
-
-ul.mw-gallery-packed li.gallerybox div.thumb img,
-ul.mw-gallery-packed-overlay li.gallerybox div.thumb img,
-ul.mw-gallery-packed-hover li.gallerybox div.thumb img {
- margin: 0 auto;
-}
-
-ul.mw-gallery-packed-hover li.gallerybox,
-ul.mw-gallery-packed-overlay li.gallerybox {
- position: relative;
-}
-
-ul.mw-gallery-packed-hover div.gallerytextwrapper {
- overflow: hidden;
- height: 0;
-}
-
-ul.mw-gallery-packed-hover li.gallerybox:hover div.gallerytextwrapper,
-ul.mw-gallery-packed-overlay li.gallerybox div.gallerytextwrapper,
-ul.mw-gallery-packed-hover li.gallerybox.mw-gallery-focused div.gallerytextwrapper {
- position: absolute;
- background: white;
- background: rgba(255, 255, 255, 0.8);
- padding: 5px 10px;
- bottom: 0;
- left: 0; /* Needed for IE */
- height: auto;
- font-weight: bold;
- margin: 2px; /* correspond to style on div.thumb */
-}
-
-ul.mw-gallery-packed-hover,
-ul.mw-gallery-packed-overlay,
-ul.mw-gallery-packed {
- text-align: center;
-}
-
.mw-ajax-loader {
- /* @embed */
background-image: url(images/ajax-loader.gif);
background-position: center center;
background-repeat: no-repeat;
@@ -888,7 +651,6 @@ ul.mw-gallery-packed {
.mw-small-spinner {
padding: 10px !important;
margin-right: 0.6em;
- /* @embed */
background-image: url(images/spinner.gif);
background-position: center center;
background-repeat: no-repeat;
@@ -945,6 +707,7 @@ h2:lang(te), h3:lang(te), h4:lang(te), h5:lang(te), h6:lang(te) {
}
/* Localised ordered list numbering for some languages */
+ol:lang(azb) li,
ol:lang(bcc) li,
ol:lang(bgn) li,
ol:lang(bqi) li,
@@ -952,13 +715,14 @@ ol:lang(fa) li,
ol:lang(glk) li,
ol:lang(kk-arab) li,
ol:lang(lrc) li,
-ol:lang(mzn) li,
-ol:lang(sdh) li {
+ol:lang(luz) li,
+ol:lang(mzn) li {
list-style-type: -moz-persian;
list-style-type: persian;
}
-ol:lang(ckb) li {
+ol:lang(ckb) li,
+ol:lang(sdh) li {
list-style-type: -moz-arabic-indic;
list-style-type: arabic-indic;
}
@@ -1026,7 +790,6 @@ ol:lang(or) li {
margin-left: 2px;
margin-bottom: -8px;
padding: 0 0 0 15px;
- /* @embed */
background-image: url(images/help-question.gif);
background-position: left center;
background-repeat: no-repeat;
@@ -1037,7 +800,6 @@ ol:lang(or) li {
}
.mw-help-field-hint:hover {
- /* @embed */
background-image: url(images/help-question-hover.gif);
}
diff --git a/resources/src/mediawiki.legacy/wikibits.js b/resources/src/mediawiki.legacy/wikibits.js
index 32cd79a5..7d1f6d73 100644
--- a/resources/src/mediawiki.legacy/wikibits.js
+++ b/resources/src/mediawiki.legacy/wikibits.js
@@ -85,7 +85,7 @@
// Execute the queued functions
for ( i = 0; i < functs.length; i++ ) {
- functs[i]();
+ functs[ i ]();
}
} );
@@ -164,33 +164,26 @@
* 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 );
- }
-
/**
* @deprecated since 1.17 Use mw.loader instead. Warnings added in 1.25.
*/
function importScriptURI( url ) {
- if ( loadedScripts[url] ) {
+ if ( loadedScripts[ url ] ) {
return null;
}
- loadedScripts[url] = true;
+ loadedScripts[ url ] = true;
var s = document.createElement( 'script' );
s.setAttribute( 'src', url );
s.setAttribute( 'type', 'text/javascript' );
- document.getElementsByTagName( 'head' )[0].appendChild( s );
+ document.getElementsByTagName( 'head' )[ 0 ].appendChild( s );
return s;
}
- function importStylesheet( page ) {
+ function importScript( page ) {
var uri = mw.config.get( 'wgScript' ) + '?title=' +
mw.util.wikiUrlencode( page ) +
- '&action=raw&ctype=text/css';
- return importStylesheetURI( uri );
+ '&action=raw&ctype=text/javascript';
+ return importScriptURI( uri );
}
/**
@@ -203,10 +196,17 @@
if ( media ) {
l.media = media;
}
- document.getElementsByTagName( 'head' )[0].appendChild( l );
+ document.getElementsByTagName( 'head' )[ 0 ].appendChild( l );
return l;
}
+ function importStylesheet( page ) {
+ var uri = mw.config.get( 'wgScript' ) + '?title=' +
+ mw.util.wikiUrlencode( page ) +
+ '&action=raw&ctype=text/css';
+ return importStylesheetURI( uri );
+ }
+
msg = 'Use mw.loader instead.';
mw.log.deprecate( win, 'loadedScripts', loadedScripts, msg );
mw.log.deprecate( win, 'importScriptURI', importScriptURI, msg );
@@ -215,4 +215,12 @@
win.importScript = importScript;
win.importStylesheet = importStylesheet;
+ // Replace document.write/writeln with basic html parsing that appends
+ // to the <body> to avoid blanking pages. Added JavaScript will not run.
+ $.each( [ 'write', 'writeln' ], function ( idx, method ) {
+ mw.log.deprecate( document, method, function () {
+ $( 'body' ).append( $.parseHTML( Array.prototype.join.call( arguments, '' ) ) );
+ }, 'Use jQuery or mw.loader.load instead.' );
+ } );
+
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.less/mediawiki.mixins.less b/resources/src/mediawiki.less/mediawiki.mixins.less
index 3366f1e1..79549c33 100644
--- a/resources/src/mediawiki.less/mediawiki.mixins.less
+++ b/resources/src/mediawiki.less/mediawiki.mixins.less
@@ -52,7 +52,7 @@
.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;
+ list-style-image: e('/* @embed */') url(@fallback) e('\9');
}
.transition(@value) {
@@ -85,7 +85,7 @@
column-width: @value;// IE 10+
}
-.column-break-inside-avoid {
+.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 2d684572..1b31956d 100644
--- a/resources/src/mediawiki.less/mediawiki.ui/mixins.less
+++ b/resources/src/mediawiki.less/mediawiki.ui/mixins.less
@@ -33,18 +33,17 @@
// Button styling
// ----------------------------------------------------------------------------
-.button-colors(@bgColor) {
+.button-colors(@bgColor, @highlightColor, @activeColor) {
background: @bgColor;
&: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%);
+ background-color: @highlightColor;
}
&:focus {
- border-color: rgba(0,0,0,0.2);
- box-shadow: inset 0 0 0 1px rgba(0,0,0,0.2);
+ border-color: @colorWhite;
+ box-shadow: 0 0 0 1px @highlightColor;
outline: none;
// remove outline in Firefox
@@ -55,15 +54,12 @@
&:active,
&.mw-ui-checked {
- // lessphp doesn't implement shade (https://github.com/leafo/lessphp/issues/528);
- // it passes it through, then ResourceLoader drops it.
- // background: shade(@bgColor, 20%);
- background: mix(#000, @bgColor, 20%);
+ background: @activeColor;
box-shadow: none;
}
}
-.button-colors(@bgColor) when (lightness(@bgColor) >= 70%) {
+.button-colors(@bgColor, @highlightColor, @activeColor) when (lightness(@bgColor) >= 70%) {
color: @colorButtonText;
border: 1px solid @colorGray12;
@@ -74,6 +70,10 @@
color: @colorButtonText;
}
+ &:focus {
+ background-color: @highlightColor;
+ }
+
&:disabled {
color: @colorDisabledText;
@@ -86,7 +86,7 @@
}
}
-.button-colors(@bgColor) when (lightness(@bgColor) < 70%) {
+.button-colors(@bgColor, @highlightColor, @activeColor) 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 and width
@@ -106,21 +106,20 @@
}
}
-.button-colors-quiet(@textColor) {
+.button-colors-quiet(@textColor, @highlightColor, @activeColor) {
// Quiet buttons all start gray, and reveal
// constructive/progressive/destructive color on hover and active.
color: @colorButtonText;
&:hover,
&:focus {
+ background: transparent;
color: @textColor;
}
&:active,
&.mw-ui-checked {
- // lessphp doesn't implement shade, see above
- // color: shade(@textColor, 20%);
- color: mix(#000, @textColor, 20%);
+ color: @activeColor;
}
&:disabled {
diff --git a/resources/src/mediawiki.less/mediawiki.ui/variables.less b/resources/src/mediawiki.less/mediawiki.ui/variables.less
index e91302be..4b6bb48b 100644
--- a/resources/src/mediawiki.less/mediawiki.ui/variables.less
+++ b/resources/src/mediawiki.less/mediawiki.ui/variables.less
@@ -21,12 +21,18 @@
// Semantic background colors
// Blue; for contextual use of a continuing action
@colorProgressive: #347bff;
+@colorProgressiveHighlight: #2962CC;
+@colorProgressiveActive: #2962CC;
// Green; for contextual use of a positive finalizing action
@colorConstructive: #00af89;
+@colorConstructiveHighlight: #008C6D;
+@colorConstructiveActive: #008C6D;
// Orange; for contextual use of returning to a past action
@colorRegressive: #FF5D00;
// Red; for contextual use of a negative action of high severity
@colorDestructive: #d11d13;
+@colorDestructiveHighlight: #A7170F;
+@colorDestructiveActive: #A7170F;
// Orange; for contextual use of a potentially negative action of medium severity
@colorMediumSevere: #FF5D00;
// Yellow; for contextual use of a potentially negative action of low severity
@@ -41,6 +47,8 @@
@colorText: @colorGray2;
@colorTextLight: @colorGray6;
@colorButtonText: @colorGray5;
+@colorButtonTextHighlight: @colorGray7;
+@colorButtonTextActive: @colorGray7;
@colorDisabledText: @colorGray12;
@colorErrorText: #CC0000;
@@ -60,3 +68,8 @@
// Global border radius to be used to buttons and inputs
@borderRadius: 2px;
+
+
+// Icon related variables
+@iconSize: 1.5em;
+@iconGutterWidth: 1em;
diff --git a/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.factory.js b/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.factory.js
index 9d280800..6f9aa025 100644
--- a/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.factory.js
+++ b/resources/src/mediawiki.messagePoster/mediawiki.messagePoster.factory.js
@@ -24,11 +24,11 @@
* @param {Function} messagePosterConstructor Constructor for MessagePoster
*/
MwMessagePosterFactory.prototype.register = function ( contentModel, messagePosterConstructor ) {
- if ( this.contentModelToClass[contentModel] !== undefined ) {
+ if ( this.contentModelToClass[ contentModel ] !== undefined ) {
throw new Error( 'The content model \'' + contentModel + '\' is already registered.' );
}
- this.contentModelToClass[contentModel] = messagePosterConstructor;
+ this.contentModelToClass[ contentModel ] = messagePosterConstructor;
};
/**
@@ -38,7 +38,7 @@
* @param {string} contentModel Content model to unregister
*/
MwMessagePosterFactory.prototype.unregister = function ( contentModel ) {
- delete this.contentModelToClass[contentModel];
+ delete this.contentModelToClass[ contentModel ];
};
/**
@@ -67,9 +67,9 @@
indexpageids: 1,
titles: title.getPrefixedDb()
} ).then( function ( result ) {
- if ( result.query.pageids.length > 0 ) {
- pageId = result.query.pageids[0];
- page = result.query.pages[pageId];
+ if ( result.query.pageids && result.query.pageids.length > 0 ) {
+ pageId = result.query.pageids[ 0 ];
+ page = result.query.pages[ pageId ];
contentModel = page.contentmodel;
moduleName = 'mediawiki.messagePoster.' + contentModel;
@@ -100,7 +100,7 @@
*
*/
MwMessagePosterFactory.prototype.createForContentModel = function ( contentModel, title ) {
- return new this.contentModelToClass[contentModel]( title );
+ return new this.contentModelToClass[ contentModel ]( title );
};
mw.messagePoster = {
diff --git a/resources/src/mediawiki.page/mediawiki.page.gallery.css b/resources/src/mediawiki.page/mediawiki.page.gallery.css
new file mode 100644
index 00000000..20deb214
--- /dev/null
+++ b/resources/src/mediawiki.page/mediawiki.page.gallery.css
@@ -0,0 +1,101 @@
+/* Galleries */
+/* These display attributes look nonsensical, but are needed to support IE and FF2 */
+/* Don't forget to update mediawiki.page.gallery.print.css */
+li.gallerybox {
+ vertical-align: top;
+ display: -moz-inline-box;
+ display: inline-block;
+}
+
+ul.gallery,
+li.gallerybox {
+ zoom: 1;
+ *display: inline;
+}
+
+ul.gallery {
+ margin: 2px;
+ padding: 2px;
+ display: block;
+}
+
+li.gallerycaption {
+ font-weight: bold;
+ text-align: center;
+ display: block;
+ word-wrap: break-word;
+}
+
+li.gallerybox div.thumb {
+ text-align: center;
+ border: 1px solid #ccc;
+ background-color: #f9f9f9;
+ margin: 2px;
+}
+
+li.gallerybox div.thumb img {
+ display: block;
+ margin: 0 auto;
+}
+
+div.gallerytext {
+ overflow: hidden;
+ font-size: 94%;
+ padding: 2px 4px;
+ word-wrap: break-word;
+}
+
+/* new gallery stuff */
+ul.mw-gallery-nolines li.gallerybox div.thumb {
+ background-color: transparent;
+ border: none;
+}
+
+ul.mw-gallery-nolines li.gallerybox div.gallerytext {
+ text-align: center;
+}
+
+/* height constrained gallery */
+
+ul.mw-gallery-packed li.gallerybox div.thumb,
+ul.mw-gallery-packed-overlay li.gallerybox div.thumb,
+ul.mw-gallery-packed-hover li.gallerybox div.thumb {
+ background-color: transparent;
+ border: none;
+}
+
+ul.mw-gallery-packed li.gallerybox div.thumb img,
+ul.mw-gallery-packed-overlay li.gallerybox div.thumb img,
+ul.mw-gallery-packed-hover li.gallerybox div.thumb img {
+ margin: 0 auto;
+}
+
+ul.mw-gallery-packed-hover li.gallerybox,
+ul.mw-gallery-packed-overlay li.gallerybox {
+ position: relative;
+}
+
+ul.mw-gallery-packed-hover div.gallerytextwrapper {
+ overflow: hidden;
+ height: 0;
+}
+
+ul.mw-gallery-packed-hover li.gallerybox:hover div.gallerytextwrapper,
+ul.mw-gallery-packed-overlay li.gallerybox div.gallerytextwrapper,
+ul.mw-gallery-packed-hover li.gallerybox.mw-gallery-focused div.gallerytextwrapper {
+ position: absolute;
+ background: white;
+ background: rgba(255, 255, 255, 0.8);
+ padding: 5px 10px;
+ bottom: 0;
+ left: 0; /* Needed for IE */
+ height: auto;
+ font-weight: bold;
+ margin: 2px; /* correspond to style on div.thumb */
+}
+
+ul.mw-gallery-packed-hover,
+ul.mw-gallery-packed-overlay,
+ul.mw-gallery-packed {
+ text-align: center;
+}
diff --git a/resources/src/mediawiki.page/mediawiki.page.gallery.js b/resources/src/mediawiki.page/mediawiki.page.gallery.js
index 95140704..dfccf215 100644
--- a/resources/src/mediawiki.page/mediawiki.page.gallery.js
+++ b/resources/src/mediawiki.page/mediawiki.page.gallery.js
@@ -12,6 +12,7 @@
/**
* Perform the layout justification.
+ *
* @ignore
* @context {HTMLElement} A `ul.mw-gallery-*` element
*/
@@ -30,14 +31,14 @@
$this = $( this );
if ( top !== lastTop ) {
- rows[rows.length] = [];
+ rows[ rows.length ] = [];
lastTop = top;
}
$img = $this.find( 'div.thumb a.image img' );
- if ( $img.length && $img[0].height ) {
- imgHeight = $img[0].height;
- imgWidth = $img[0].width;
+ 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
@@ -54,7 +55,7 @@
}
captionWidth = $this.children().children( 'div.gallerytextwrapper' ).width();
- rows[rows.length - 1][rows[rows.length - 1].length] = {
+ rows[ rows.length - 1 ][ rows[ rows.length - 1 ].length ] = {
$elm: $this,
width: $this.outerWidth(),
imgWidth: imgWidth,
@@ -96,25 +97,25 @@
maxWidth = $gallery.width();
combinedAspect = 0;
combinedPadding = 0;
- curRow = rows[i];
+ curRow = rows[ i ];
curRowHeight = 0;
for ( j = 0; j < curRow.length; j++ ) {
if ( curRowHeight === 0 ) {
- if ( isFinite( curRow[j].height ) ) {
+ if ( isFinite( curRow[ j ].height ) ) {
// Get the height of this row, by taking the first
// non-out of bounds height
- curRowHeight = curRow[j].height;
+ curRowHeight = curRow[ j ].height;
}
}
- if ( curRow[j].aspect === 0 || !isFinite( curRow[j].aspect ) ) {
+ 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;
+ combinedPadding += curRow[ j ].width;
} else {
- combinedAspect += curRow[j].aspect;
- combinedPadding += curRow[j].width - curRow[j].imgWidth;
+ combinedAspect += curRow[ j ].aspect;
+ combinedPadding += curRow[ j ].width - curRow[ j ].imgWidth;
}
}
@@ -162,13 +163,13 @@
}
for ( j = 0; j < curRow.length; j++ ) {
- newWidth = preferredHeight * curRow[j].aspect;
- padding = curRow[j].width - curRow[j].imgWidth;
- $outerDiv = curRow[j].$elm;
+ 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;
+ imageElm = $imageElm.length ? $imageElm[ 0 ] : null;
$caption = $outerDiv.find( 'div.gallerytextwrapper' );
// Since we are going to re-adjust the height, the vertical
@@ -187,7 +188,7 @@
$outerDiv.width( newWidth + padding );
$innerDiv.width( newWidth + padding );
$imageDiv.width( newWidth );
- $caption.width( curRow[j].captionWidth + ( newWidth - curRow[j].imgWidth ) );
+ $caption.width( curRow[ j ].captionWidth + ( newWidth - curRow[ j ].imgWidth ) );
}
if ( imageElm ) {
@@ -220,7 +221,7 @@
$( this ).find( 'div.gallerytextwrapper' ).width( captionWidth );
$imageElm = $( this ).find( 'img' ).first();
- imageElm = $imageElm.length ? $imageElm[0] : null;
+ imageElm = $imageElm.length ? $imageElm[ 0 ] : null;
if ( imageElm ) {
imageElm.width = imgWidth;
imageElm.height = imgHeight;
diff --git a/resources/src/mediawiki.page/mediawiki.page.gallery.print.css b/resources/src/mediawiki.page/mediawiki.page.gallery.print.css
new file mode 100644
index 00000000..0c14865e
--- /dev/null
+++ b/resources/src/mediawiki.page/mediawiki.page.gallery.print.css
@@ -0,0 +1,35 @@
+li.gallerybox {
+ vertical-align: top;
+ display: inline-block;
+}
+
+ul.gallery, li.gallerybox {
+ zoom: 1;
+ *display: inline;
+}
+
+ul.gallery {
+ margin: 2px;
+ padding: 2px;
+ display: block;
+}
+
+li.gallerycaption {
+ font-weight: bold;
+ text-align: center;
+ display: block;
+ word-wrap: break-word;
+}
+
+li.gallerybox div.thumb {
+ text-align: center;
+ border: 1px solid #ccc;
+ margin: 2px;
+}
+
+div.gallerytext {
+ overflow: hidden;
+ font-size: 94%;
+ padding: 2px 4px;
+ word-wrap: break-word;
+}
diff --git a/resources/src/mediawiki.page/mediawiki.page.image.pagination.js b/resources/src/mediawiki.page/mediawiki.page.image.pagination.js
index 9ad9c30a..49a51dfc 100644
--- a/resources/src/mediawiki.page/mediawiki.page.image.pagination.js
+++ b/resources/src/mediawiki.page/mediawiki.page.image.pagination.js
@@ -2,6 +2,7 @@
* Implement AJAX navigation for multi-page images so the user may browse without a full page reload.
*/
( function ( mw, $ ) {
+ /*jshint latedef:false */
var jqXhr, $multipageimage, $spinner,
cache = {},
cacheOrder = [];
@@ -18,11 +19,11 @@
jqXhr = undefined;
// Try the cache
- if ( cache[url] ) {
+ if ( cache[ url ] ) {
// Update access freshness
cacheOrder.splice( $.inArray( url, cacheOrder ), 1 );
cacheOrder.push( url );
- return $.Deferred().resolve( cache[url] ).promise();
+ return $.Deferred().resolve( cache[ url ] ).promise();
}
// @todo Don't fetch the entire page. Ideally we'd only fetch the content portion or the data
@@ -36,12 +37,12 @@
jqXhr = undefined;
// Cache the newly loaded page
- cache[url] = $contents;
+ cache[ url ] = $contents;
cacheOrder.push( url );
// Remove the oldest entry if we're over the limit
if ( cacheOrder.length > 10 ) {
- delete cache[ cacheOrder[0] ];
+ delete cache[ cacheOrder[ 0 ] ];
cacheOrder = cacheOrder.slice( 1 );
}
} );
diff --git a/resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js b/resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js
index cc72e168..f9b0d356 100644
--- a/resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js
+++ b/resources/src/mediawiki.page/mediawiki.page.patrol.ajax.js
@@ -17,7 +17,7 @@
var $spinner, href, rcid, apiRequest;
// Start preloading the notification module (normally loaded by mw.notify())
- mw.loader.load( ['mediawiki.notification'], null, true );
+ mw.loader.load( 'mediawiki.notification' );
// Hide the link and create a spinner to show it inside the brackets.
$spinner = $.createSpinner( {
@@ -43,7 +43,7 @@
mw.notify( mw.msg( 'markedaspatrollednotify', title.toText() ) );
} else {
// This should never happen as errors should trigger fail
- mw.notify( mw.msg( 'markedaspatrollederrornotify' ) );
+ mw.notify( mw.msg( 'markedaspatrollederrornotify' ), { type: 'error' } );
}
} )
.fail( function ( error ) {
@@ -53,9 +53,9 @@
$patrolLinks.show();
if ( error === 'noautopatrol' ) {
// Can't patrol own
- mw.notify( mw.msg( 'markedaspatrollederror-noautopatrol' ) );
+ mw.notify( mw.msg( 'markedaspatrollederror-noautopatrol' ), { type: 'warn' } );
} else {
- mw.notify( mw.msg( 'markedaspatrollederrornotify' ) );
+ mw.notify( mw.msg( 'markedaspatrollederrornotify' ), { type: 'error' } );
}
} );
diff --git a/resources/src/mediawiki.page/mediawiki.page.ready.js b/resources/src/mediawiki.page/mediawiki.page.ready.js
index 36eb9d4f..9505bdd1 100644
--- a/resources/src/mediawiki.page/mediawiki.page.ready.js
+++ b/resources/src/mediawiki.page/mediawiki.page.ready.js
@@ -59,6 +59,17 @@
}
$nodes.updateTooltipAccessKeys();
+ // Infuse OOUI widgets, if any are present
+ $nodes = $( '[data-ooui]' );
+ if ( $nodes.length ) {
+ // FIXME: We should only load the widgets that are being infused
+ mw.loader.using( [ 'mediawiki.widgets', 'mediawiki.widgets.UserInputWidget' ] ).done( function () {
+ $nodes.each( function () {
+ OO.ui.infuse( this );
+ } );
+ } );
+ }
+
} );
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.page/mediawiki.page.startup.js b/resources/src/mediawiki.page/mediawiki.page.startup.js
index ddd4f0c4..708dcb5c 100644
--- a/resources/src/mediawiki.page/mediawiki.page.startup.js
+++ b/resources/src/mediawiki.page/mediawiki.page.startup.js
@@ -1,12 +1,11 @@
( function ( mw, $ ) {
- mw.page = {};
+ // Support: MediaWiki < 1.26
+ // Cached HTML will not yet have this from OutputPage::getHeadScripts.
+ document.documentElement.className = document.documentElement.className
+ .replace( /(^|\s)client-nojs(\s|$)/, '$1client-js$2' );
- // Client profile classes for <html>
- // Allows for easy hiding/showing of JS or no-JS-specific UI elements
- $( document.documentElement )
- .addClass( 'client-js' )
- .removeClass( 'client-nojs' );
+ mw.page = {};
$( function () {
mw.util.init();
diff --git a/resources/src/mediawiki.page/mediawiki.page.watch.ajax.js b/resources/src/mediawiki.page/mediawiki.page.watch.ajax.js
index d252f0e4..a3197da3 100644
--- a/resources/src/mediawiki.page/mediawiki.page.watch.ajax.js
+++ b/resources/src/mediawiki.page/mediawiki.page.watch.ajax.js
@@ -84,12 +84,12 @@
actionPaths = mw.config.get( 'wgActionPaths' );
for ( key in actionPaths ) {
if ( actionPaths.hasOwnProperty( key ) ) {
- parts = actionPaths[key].split( '$1' );
+ parts = actionPaths[ key ].split( '$1' );
for ( i = 0; i < parts.length; i++ ) {
- parts[i] = $.escapeRE( parts[i] );
+ parts[ i ] = mw.RegExp.escape( parts[ i ] );
}
m = new RegExp( parts.join( '(.+)' ) ).exec( url );
- if ( m && m[1] ) {
+ if ( m && m[ 1 ] ) {
return key;
}
@@ -116,7 +116,7 @@
var action, api, $link;
// Start preloading the notification module (normally loaded by mw.notify())
- mw.loader.load( ['mediawiki.notification'], null, true );
+ mw.loader.load( 'mediawiki.notification' );
action = mwUriGetAction( this.href );
@@ -138,7 +138,7 @@
api = new mw.Api();
- api[action]( title )
+ api[ action ]( title )
.done( function ( watchResponse ) {
var otherAction = action === 'watch' ? 'unwatch' : 'watch';
@@ -170,7 +170,10 @@
msg = mw.message( 'watcherrortext', link );
// Report to user about the error
- mw.notify( msg, { tag: 'watch-self' } );
+ mw.notify( msg, {
+ tag: 'watch-self',
+ type: 'error'
+ } );
} );
} );
} );
diff --git a/resources/src/mediawiki.skinning/content.css b/resources/src/mediawiki.skinning/content.css
index 7dd5ee7f..454fe58d 100644
--- a/resources/src/mediawiki.skinning/content.css
+++ b/resources/src/mediawiki.skinning/content.css
@@ -23,14 +23,13 @@
* We use display:table. Even though it should only contain other table-* display
* elements, there are no known problems with using this.
*
- * Because IE < 8, FF 2 and other older browsers don't support display:table, we fallback to
+ * Because IE < 8 and other older browsers don't support display:table, we fallback to
* using inline-block mode, which features at least intrinsic width, but won't clear preceding
* inline elements. In practice inline elements surrounding the TOC are uncommon enough that
* this is an acceptable sacrifice.
*/
#toc,
.toc {
- display: -moz-inline-block;
display: inline-block;
display: table;
diff --git a/resources/src/mediawiki.skinning/elements.css b/resources/src/mediawiki.skinning/elements.css
index 8140d1a5..d706d261 100644
--- a/resources/src/mediawiki.skinning/elements.css
+++ b/resources/src/mediawiki.skinning/elements.css
@@ -64,6 +64,10 @@ a.new:visited, #p-personal a.new:visited {
color: #b63;
}
+.mw-body a.external.free {
+ word-wrap: break-word;
+}
+
/* Inline Elements */
img {
border: none;
@@ -194,11 +198,14 @@ code {
padding: 1px 4px;
}
-pre, .mw-code {
+pre,
+.mw-code {
color: black;
background-color: #f9f9f9;
border: 1px solid #ddd;
padding: 1em;
+ /* Wrap lines in overflow. T2260, T103780 */
+ white-space: pre-wrap;
}
/* Tables */
@@ -237,10 +244,6 @@ textarea {
box-sizing: border-box;
}
-select {
- vertical-align: top;
-}
-
/* Emulate Center */
.center {
width: 100%;
diff --git a/resources/src/mediawiki.special/mediawiki.special.changeemail.js b/resources/src/mediawiki.special/mediawiki.special.changeemail.js
index 67531f78..06851b93 100644
--- a/resources/src/mediawiki.special/mediawiki.special.changeemail.js
+++ b/resources/src/mediawiki.special/mediawiki.special.changeemail.js
@@ -4,6 +4,7 @@
( function ( mw, $ ) {
/**
* Given an email validity status (true, false, null) update the label CSS class
+ *
* @ignore
*/
function updateMailValidityLabel( mail ) {
diff --git a/resources/src/mediawiki.special/mediawiki.special.changeslist.css b/resources/src/mediawiki.special/mediawiki.special.changeslist.css
index 16fdf38a..bdae0dd2 100644
--- a/resources/src/mediawiki.special/mediawiki.special.changeslist.css
+++ b/resources/src/mediawiki.special/mediawiki.special.changeslist.css
@@ -7,9 +7,11 @@
}
/*
- * Titles, including username links, are especially prone for getting jumbled up
+ * Titles, including username links, and also tag names
+ * are prone to getting jumbled up
* with other titles, usernames, etc. in mixed RTL-LTR environment.
*/
+.mw-changeslist .mw-tag-marker,
.mw-changeslist .mw-title {
unicode-bidi: embed;
}
diff --git a/resources/src/mediawiki.special/mediawiki.special.changeslist.enhanced.css b/resources/src/mediawiki.special/mediawiki.special.changeslist.enhanced.css
index 0e026aff..a4843509 100644
--- a/resources/src/mediawiki.special/mediawiki.special.changeslist.enhanced.css
+++ b/resources/src/mediawiki.special/mediawiki.special.changeslist.enhanced.css
@@ -59,3 +59,7 @@ table.mw-enhanced-rc td.mw-enhanced-rc-nested {
.mw-enhanced-watched .mw-enhanced-rc-time {
font-weight: bold;
}
+
+span.changedby {
+ font-size: 95%;
+}
diff --git a/resources/src/mediawiki.special/mediawiki.special.changeslist.legend.js b/resources/src/mediawiki.special/mediawiki.special.changeslist.legend.js
index c9e55111..f217bf59 100644
--- a/resources/src/mediawiki.special/mediawiki.special.changeslist.legend.js
+++ b/resources/src/mediawiki.special/mediawiki.special.changeslist.legend.js
@@ -3,23 +3,22 @@
*/
/* Remember the collapse state of the legend on recent changes and watchlist pages. */
-jQuery( document ).ready( function ( $ ) {
+( function ( mw, $ ) {
var
cookieName = 'changeslist-state',
- cookieOptions = {
- expires: 30,
- path: '/'
- },
- isCollapsed = $.cookie( cookieName ) === 'collapsed';
+ // Expanded by default
+ isCollapsed = mw.cookie.get( cookieName ) === 'collapsed';
- $( '.mw-changeslist-legend' )
- .makeCollapsible( {
- collapsed: isCollapsed
- } )
- .on( 'beforeExpand.mw-collapsible', function () {
- $.cookie( cookieName, 'expanded', cookieOptions );
- } )
- .on( 'beforeCollapse.mw-collapsible', function () {
- $.cookie( cookieName, 'collapsed', cookieOptions );
- } );
-} );
+ $( function () {
+ $( '.mw-changeslist-legend' )
+ .makeCollapsible( {
+ collapsed: isCollapsed
+ } )
+ .on( 'beforeExpand.mw-collapsible', function () {
+ mw.cookie.set( cookieName, 'expanded' );
+ } )
+ .on( 'beforeCollapse.mw-collapsible', function () {
+ mw.cookie.set( cookieName, 'collapsed' );
+ } );
+ } );
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.special/mediawiki.special.css b/resources/src/mediawiki.special/mediawiki.special.css
index d2457262..a13ec3cc 100644
--- a/resources/src/mediawiki.special/mediawiki.special.css
+++ b/resources/src/mediawiki.special/mediawiki.special.css
@@ -84,13 +84,10 @@ td#mw-prefixindex-nav-form {
font-weight: bold;
}
-.mw-specialpages-table {
- margin-top: -1em;
- margin-bottom: 1em;
-}
-
-.mw-specialpages-table td {
- vertical-align: top;
+.mw-specialpages-list {
+ -webkit-columns: 16em 2;
+ -moz-columns: 16em 2;
+ columns: 16em 2;
}
/* Special:Statistics */
diff --git a/resources/src/mediawiki.special/mediawiki.special.movePage.css b/resources/src/mediawiki.special/mediawiki.special.movePage.css
new file mode 100644
index 00000000..dd1c2aad
--- /dev/null
+++ b/resources/src/mediawiki.special/mediawiki.special.movePage.css
@@ -0,0 +1,8 @@
+/*!
+ * Styles for Special:MovePage
+ */
+
+.movepage-wrapper {
+ width: 50em;
+ margin: 1em 0;
+}
diff --git a/resources/src/mediawiki.special/mediawiki.special.movePage.js b/resources/src/mediawiki.special/mediawiki.special.movePage.js
index 7e56050d..6d88c51c 100644
--- a/resources/src/mediawiki.special/mediawiki.special.movePage.js
+++ b/resources/src/mediawiki.special/mediawiki.special.movePage.js
@@ -1,6 +1,7 @@
/*!
* JavaScript for Special:MovePage
*/
-jQuery( function ( $ ) {
- $( '#wpReason, #wpNewTitleMain' ).byteLimit();
+jQuery( function () {
+ OO.ui.infuse( 'wpNewTitle' );
+ OO.ui.infuse( 'wpReason' ).$input.byteLimit();
} );
diff --git a/resources/src/mediawiki.special/mediawiki.special.preferences.css b/resources/src/mediawiki.special/mediawiki.special.preferences.css
index e27e34a0..9e5efd36 100644
--- a/resources/src/mediawiki.special/mediawiki.special.preferences.css
+++ b/resources/src/mediawiki.special/mediawiki.special.preferences.css
@@ -19,3 +19,20 @@
height: 0;
zoom: 1;
}
+
+/* When JS is enabled, .mw-preferences-messageboxes are replaced with mw.notifications */
+.mw-preferences-messagebox {
+ display: none;
+}
+
+.prefsection td.mw-label {
+ width: 20%;
+}
+
+.prefsection table {
+ width: 100%;
+}
+
+.prefsection table.mw-htmlform-matrix {
+ width: auto;
+}
diff --git a/resources/src/mediawiki.special/mediawiki.special.preferences.js b/resources/src/mediawiki.special/mediawiki.special.preferences.js
index 4bd747b2..6839d813 100644
--- a/resources/src/mediawiki.special/mediawiki.special.preferences.js
+++ b/resources/src/mediawiki.special/mediawiki.special.preferences.js
@@ -5,7 +5,8 @@ jQuery( function ( $ ) {
var $preftoc, $preferences, $fieldsets, $legends,
hash, labelFunc,
$tzSelect, $tzTextbox, $localtimeHolder, servertime,
- $checkBoxes, allowCloseWindowFn;
+ $checkBoxes, allowCloseWindow,
+ notif;
labelFunc = function () {
return this.id.replace( /^mw-prefsection/g, 'preftab' );
@@ -50,8 +51,8 @@ jQuery( function ( $ ) {
* It uses document.getElementById for security reasons (HTML injections in $()).
*
* @ignore
- * @param String name: the name of a tab without the prefix ("mw-prefsection-")
- * @param String mode: [optional] A hash will be set according to the current
+ * @param {String} name the name of a tab without the prefix ("mw-prefsection-")
+ * @param {String} [mode] A hash will be set according to the current
* open section. Set mode 'noHash' to surpress this.
*/
function switchPrefTab( name, mode ) {
@@ -84,6 +85,26 @@ jQuery( function ( $ ) {
}
}
+ // Check for messageboxes (.successbox, .warningbox, .errorbox) to replace with notifications
+ if ( $( '.mw-preferences-messagebox' ).length ) {
+ // If there is a #mw-preferences-success box and javascript is enabled, use a slick notification instead!
+ if ( $( '#mw-preferences-success' ).length ) {
+ notif = mediaWiki.notification.notify( mediaWiki.message( 'savedprefs' ), { autoHide: false } );
+ // 'change' event not reliable!
+ $( '#preftoc, .prefsection' ).one( 'change keydown mousedown', function () {
+ if ( notif ) {
+ notif.close();
+ notif = null;
+ }
+ } );
+
+ // Remove now-unnecessary success=1 querystring to prevent reappearance of notification on reload
+ if ( history.replaceState ) {
+ history.replaceState( {}, document.title, location.href.replace( /&?success=1/, '' ) );
+ }
+ }
+ }
+
// Populate the prefToc
$legends.each( function ( i, legend ) {
var $legend = $( legend ),
@@ -183,15 +204,15 @@ jQuery( function ( $ ) {
var minutes,
arr = hour.split( ':' );
- arr[0] = parseInt( arr[0], 10 );
+ arr[ 0 ] = parseInt( arr[ 0 ], 10 );
if ( arr.length === 1 ) {
// Specification is of the form [-]XX
- minutes = arr[0] * 60;
+ minutes = arr[ 0 ] * 60;
} else {
// Specification is of the form [-]XX:XX
- minutes = Math.abs( arr[0] ) * 60 + parseInt( arr[1], 10 );
- if ( arr[0] < 0 ) {
+ minutes = Math.abs( arr[ 0 ] ) * 60 + parseInt( arr[ 1 ], 10 );
+ if ( arr[ 0 ] < 0 ) {
minutes *= -1;
}
}
@@ -218,7 +239,7 @@ jQuery( function ( $ ) {
minuteDiff = hoursToMinutes( $tzTextbox.val() );
} else {
// Grab data from the $tzSelect value
- minuteDiff = parseInt( type.split( '|' )[1], 10 ) || 0;
+ minuteDiff = parseInt( type.split( '|' )[ 1 ], 10 ) || 0;
$tzTextbox.val( minutesToHours( minuteDiff ) );
}
@@ -266,7 +287,7 @@ 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() );
- allowCloseWindowFn = mediaWiki.confirmCloseWindow( {
+ allowCloseWindow = mediaWiki.confirmCloseWindow( {
test: function () {
return $( '#mw-prefs-form' ).serialize() !== $( '#mw-prefs-form' ).data( 'origdata' );
},
@@ -274,6 +295,6 @@ jQuery( function ( $ ) {
message: mediaWiki.msg( 'prefswarning-warning', mediaWiki.msg( 'saveprefs' ) ),
namespace: 'prefswarning'
} );
- $( '#mw-prefs-form' ).submit( allowCloseWindowFn );
- $( '#mw-prefs-restoreprefs' ).click( allowCloseWindowFn );
+ $( '#mw-prefs-form' ).submit( $.proxy( allowCloseWindow, 'release' ) );
+ $( '#mw-prefs-restoreprefs' ).click( $.proxy( allowCloseWindow, 'release' ) );
} );
diff --git a/resources/src/mediawiki.special/mediawiki.special.search.css b/resources/src/mediawiki.special/mediawiki.special.search.css
index 8f845dfa..b8693143 100644
--- a/resources/src/mediawiki.special/mediawiki.special.search.css
+++ b/resources/src/mediawiki.special/mediawiki.special.search.css
@@ -27,6 +27,7 @@ div.searchresult {
}
.mw-search-results {
margin-left: 0.4em;
+ float: left;
}
.mw-search-results li {
padding-bottom: 1.2em;
diff --git a/resources/src/mediawiki.special/mediawiki.special.search.js b/resources/src/mediawiki.special/mediawiki.special.search.js
index b27fe349..730119e8 100644
--- a/resources/src/mediawiki.special/mediawiki.special.search.js
+++ b/resources/src/mediawiki.special/mediawiki.special.search.js
@@ -39,12 +39,12 @@
var parts = $( this ).attr( 'href' ).split( 'search=' ),
lastpart = '',
prefix = 'search=';
- if ( parts.length > 1 && parts[1].indexOf( '&' ) !== -1 ) {
- lastpart = parts[1].slice( parts[1].indexOf( '&' ) );
+ if ( parts.length > 1 && parts[ 1 ].indexOf( '&' ) !== -1 ) {
+ lastpart = parts[ 1 ].slice( parts[ 1 ].indexOf( '&' ) );
} else {
prefix = '&search=';
}
- this.href = parts[0] + prefix + encodeURIComponent( searchterm ) + lastpart;
+ this.href = parts[ 0 ] + prefix + encodeURIComponent( searchterm ) + lastpart;
} );
} ).trigger( 'change' );
diff --git a/resources/src/mediawiki.special/mediawiki.special.unwatchedPages.js b/resources/src/mediawiki.special/mediawiki.special.unwatchedPages.js
index 8d3e86ae..7628ff88 100644
--- a/resources/src/mediawiki.special/mediawiki.special.unwatchedPages.js
+++ b/resources/src/mediawiki.special/mediawiki.special.unwatchedPages.js
@@ -28,7 +28,7 @@
mw.notify( mw.msg( 'addedwatchtext-short', title ) );
} ).fail( function () {
$link.text( mw.msg( 'watch' ) );
- mw.notify( mw.msg( 'watcherrortext', title ) );
+ mw.notify( mw.msg( 'watcherrortext', title ), { type: 'error' } );
} );
} else {
$link.text( mw.msg( 'unwatching' ) );
@@ -38,7 +38,7 @@
mw.notify( mw.msg( 'removedwatchtext-short', title ) );
} ).fail( function () {
$link.text( mw.msg( 'unwatch' ) );
- mw.notify( mw.msg( 'watcherrortext', title ) );
+ mw.notify( mw.msg( 'watcherrortext', title ), { type: 'error' } );
} );
}
diff --git a/resources/src/mediawiki.special/mediawiki.special.upload.js b/resources/src/mediawiki.special/mediawiki.special.upload.js
index eeccda59..677d26d7 100644
--- a/resources/src/mediawiki.special/mediawiki.special.upload.js
+++ b/resources/src/mediawiki.special/mediawiki.special.upload.js
@@ -6,6 +6,7 @@
* @singleton
*/
( function ( mw, $ ) {
+ /*jshint latedef:false */
var uploadWarning, uploadLicense,
ajaxUploadDestCheck = mw.config.get( 'wgAjaxUploadDestCheck' ),
$license = $( '#wpLicense' );
@@ -35,7 +36,7 @@
}
// Check response cache
if ( this.responseCache.hasOwnProperty( this.nameToCheck ) ) {
- this.setWarning( this.responseCache[this.nameToCheck] );
+ this.setWarning( this.responseCache[ this.nameToCheck ] );
return;
}
@@ -71,7 +72,7 @@
} ).done( function ( result ) {
var resultOut = '';
if ( result.query ) {
- resultOut = result.query.pages[result.query.pageids[0]].imageinfo[0];
+ resultOut = result.query.pages[ result.query.pageids[ 0 ] ].imageinfo[ 0 ];
}
$spinnerDestCheck.remove();
uploadWarning.processResult( resultOut, uploadWarning.nameToCheck );
@@ -80,7 +81,7 @@
processResult: function ( result, fileName ) {
this.setWarning( result.html );
- this.responseCache[fileName] = result.html;
+ this.responseCache[ fileName ] = result.html;
},
setWarning: function ( warning ) {
@@ -107,7 +108,7 @@
return;
}
if ( this.responseCache.hasOwnProperty( license ) ) {
- this.showPreview( this.responseCache[license] );
+ this.showPreview( this.responseCache[ license ] );
return;
}
@@ -126,8 +127,8 @@
},
processResult: function ( result, license ) {
- this.responseCache[license] = result.parse.text['*'];
- this.showPreview( this.responseCache[license] );
+ this.responseCache[ license ] = result.parse.text[ '*' ];
+ this.showPreview( this.responseCache[ license ] );
},
showPreview: function ( preview ) {
@@ -228,7 +229,7 @@
fname = fname.replace( / /g, '_' );
// Capitalise first letter if needed
if ( mw.config.get( 'wgCapitalizeUploads' ) ) {
- fname = fname.charAt( 0 ).toUpperCase().concat( fname.slice( 1 ) );
+ fname = fname[ 0 ].toUpperCase() + fname.slice( 1 );
}
// Output result
@@ -265,15 +266,32 @@
* TODO: Put SVG back after working around Firefox 7 bug <https://bugzilla.wikimedia.org/show_bug.cgi?id=31643>
*
* @param {File} file
- * @return boolean
+ * @return {boolean}
*/
function fileIsPreviewable( file ) {
- var known = ['image/png', 'image/gif', 'image/jpeg', 'image/svg+xml'],
+ var known = [ 'image/png', 'image/gif', 'image/jpeg', 'image/svg+xml' ],
tooHuge = 10 * 1024 * 1024;
return ( $.inArray( file.type, known ) !== -1 ) && file.size > 0 && file.size < tooHuge;
}
/**
+ * Format a file size attractively.
+ *
+ * TODO: Match numeric formatting
+ *
+ * @param {number} s
+ * @return {string}
+ */
+ function prettySize( s ) {
+ var sizeMsgs = [ 'size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes' ];
+ while ( s >= 1024 && sizeMsgs.length > 1 ) {
+ s /= 1024;
+ sizeMsgs = sizeMsgs.slice( 1 );
+ }
+ return mw.msg( sizeMsgs[ 0 ], Math.round( s ) );
+ }
+
+ /**
* Show a thumbnail preview of PNG, JPEG, GIF, and SVG files prior to upload
* in browsers supporting HTML5 FileAPI.
*
@@ -291,13 +309,17 @@
ctx,
meta,
previewSize = 180,
+ $spinner = $.createSpinner( { size: 'small', type: 'block' } )
+ .css( { width: previewSize, height: previewSize } ),
thumb = mw.template.get( 'mediawiki.special.upload', 'thumbnail.html' ).render();
- thumb.find( '.filename' ).text( file.name ).end()
- .find( '.fileinfo' ).text( prettySize( file.size ) ).end();
+ thumb
+ .find( '.filename' ).text( file.name ).end()
+ .find( '.fileinfo' ).text( prettySize( file.size ) ).end()
+ .find( '.thumbinner' ).prepend( $spinner ).end();
- $canvas = $( '<canvas width="' + previewSize + '" height="' + previewSize + '" ></canvas>' );
- ctx = $canvas[0].getContext( '2d' );
+ $canvas = $( '<canvas>' ).attr( { width: previewSize, height: previewSize } );
+ ctx = $canvas[ 0 ].getContext( '2d' );
$( '#mw-htmlform-source' ).parent().prepend( thumb );
fetchPreview( file, function ( dataURL ) {
@@ -369,7 +391,7 @@
ctx.clearRect( 0, 0, 180, 180 );
ctx.rotate( rotation / 180 * Math.PI );
ctx.drawImage( img, x, y, width, height );
- thumb.find( '.mw-small-spinner' ).replaceWith( $canvas );
+ $spinner.replaceWith( $canvas );
// Image size
info = mw.msg( 'widthheight', logicalWidth, logicalHeight ) +
@@ -421,7 +443,7 @@
buffer = new Uint8Array( reader.result ),
string = '';
for ( i = 0; i < buffer.byteLength; i++ ) {
- string += String.fromCharCode( buffer[i] );
+ string += String.fromCharCode( buffer[ i ] );
}
callbackBinary( string );
@@ -451,23 +473,6 @@
}
/**
- * Format a file size attractively.
- *
- * TODO: Match numeric formatting
- *
- * @param {number} s
- * @return {string}
- */
- function prettySize( s ) {
- var sizeMsgs = ['size-bytes', 'size-kilobytes', 'size-megabytes', 'size-gigabytes'];
- while ( s >= 1024 && sizeMsgs.length > 1 ) {
- s /= 1024;
- sizeMsgs = sizeMsgs.slice( 1 );
- }
- return mw.msg( sizeMsgs[0], Math.round( s ) );
- }
-
- /**
* Clear the file upload preview area.
*/
function clearPreview() {
@@ -483,10 +488,10 @@
function getMaxUploadSize( type ) {
var sizes = mw.config.get( 'wgMaxUploadSize' );
- if ( sizes[type] !== undefined ) {
- return sizes[type];
+ if ( sizes[ type ] !== undefined ) {
+ return sizes[ type ];
}
- return sizes['*'];
+ return sizes[ '*' ];
}
$( '.mw-upload-source-error' ).remove();
@@ -511,7 +516,7 @@
clearPreview();
if ( this.files && this.files.length ) {
// Note: would need to be updated to handle multiple files.
- var file = this.files[0];
+ var file = this.files[ 0 ];
if ( !checkMaxUploadSize( file ) ) {
return;
@@ -578,7 +583,7 @@
} );
$uploadForm.submit( function () {
- allowCloseWindow();
+ allowCloseWindow.release();
} );
} );
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.special/mediawiki.special.userlogin.common.js b/resources/src/mediawiki.special/mediawiki.special.userlogin.common.js
deleted file mode 100644
index f5289dee..00000000
--- a/resources/src/mediawiki.special/mediawiki.special.userlogin.common.js
+++ /dev/null
@@ -1,72 +0,0 @@
-/*!
- * JavaScript for login and signup forms.
- */
-( function ( mw, $ ) {
- // Move the FancyCaptcha image into a more attractive container.
- // The CAPTCHA is in a <div class="captcha"> at the top of the form. If it's a FancyCaptcha,
- // then we remove it and insert it lower down, in a customized div with just what we need (e.g.
- // no 'fancycaptcha-createaccount' message).
- function adjustFancyCaptcha( $content, buttonSubmit ) {
- var $submit = $content.find( buttonSubmit ),
- tabIndex,
- $captchaStuff,
- $captchaImageContainer,
- // JavaScript can't yet parse the message 'createacct-imgcaptcha-help' when it
- // contains a MediaWiki transclusion, so PHP parses it and sends the HTML.
- // This is only set for the signup form (and undefined for login).
- helpMsg = mw.config.get( 'wgCreateacctImgcaptchaHelp' ),
- helpHtml = '';
-
- if ( !$submit.length ) {
- return;
- }
- tabIndex = $submit.prop( 'tabIndex' ) - 1;
- $captchaStuff = $content.find( '.captcha' );
-
- if ( $captchaStuff.length ) {
- // The FancyCaptcha has this class in the ConfirmEdit extension since 2013-04-18.
- $captchaImageContainer = $captchaStuff.find( '.fancycaptcha-image-container' );
- if ( $captchaImageContainer.length !== 1 ) {
- return;
- }
-
- $captchaStuff.remove();
-
- if ( helpMsg ) {
- helpHtml = '<small class="mw-createacct-captcha-assisted">' + helpMsg + '</small>';
- }
-
- // Insert another div before the submit button that will include the
- // repositioned FancyCaptcha div, an input field, and possible help.
- $submit.closest( 'div' ).before( [
- '<div>',
- '<label for="wpCaptchaWord">' + mw.message( 'createacct-captcha' ).escaped() + '</label>',
- '<div class="mw-createacct-captcha-container">',
- '<div class="mw-createacct-captcha-and-reload" />',
- '<input id="wpCaptchaWord" class="mw-ui-input" name="wpCaptchaWord" type="text" placeholder="' +
- mw.message( 'createacct-imgcaptcha-ph' ).escaped() +
- '" tabindex="' + tabIndex + '" autocapitalize="off" autocorrect="off">',
- helpHtml,
- '</div>',
- '</div>'
- ].join( '' ) );
-
- // Stick the FancyCaptcha container inside our bordered and framed parents.
- $captchaImageContainer
- .prependTo( $content.find( '.mw-createacct-captcha-and-reload' ) );
-
- // Find the input field, add the text (if any) of the existing CAPTCHA
- // field (although usually it's blanked out on every redisplay),
- // and after it move over the hidden field that tells the CAPTCHA
- // what to do.
- $content.find( '#wpCaptchaWord' )
- .val( $captchaStuff.find( '#wpCaptchaWord' ).val() )
- .after( $captchaStuff.find( '#wpCaptchaId' ) );
- }
- }
-
- $( function () {
- // Work with both login and signup form
- adjustFancyCaptcha( $( '#mw-content-text' ), '#wpCreateaccount, #wpLoginAttempt' );
- } );
-}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki.special/mediawiki.special.userlogin.signup.js b/resources/src/mediawiki.special/mediawiki.special.userlogin.signup.js
index a32a7902..a0c6ee2a 100644
--- a/resources/src/mediawiki.special/mediawiki.special.userlogin.signup.js
+++ b/resources/src/mediawiki.special/mediawiki.special.userlogin.signup.js
@@ -65,7 +65,7 @@
ususers: username // '|' in usernames is handled below
} )
.done( function ( resp ) {
- var userinfo = resp.query.users[0];
+ var userinfo = resp.query.users[ 0 ];
if ( resp.query.users.length !== 1 ) {
// Happens if the user types '|' into the field
diff --git a/resources/src/mediawiki.special/mediawiki.special.version.css b/resources/src/mediawiki.special/mediawiki.special.version.css
index 7c87d68f..5b259e70 100644
--- a/resources/src/mediawiki.special/mediawiki.special.version.css
+++ b/resources/src/mediawiki.special/mediawiki.special.version.css
@@ -1,10 +1,12 @@
/*!
* Styling for Special:Version
*/
-.mw-version-ext-name {
+.mw-version-ext-name,
+.mw-version-library-name {
font-weight: bold;
}
+.mw-version-ext-license,
.mw-version-ext-vcs-timestamp {
white-space: nowrap;
}
diff --git a/resources/src/mediawiki.special/templates/thumbnail.html b/resources/src/mediawiki.special/templates/thumbnail.html
index 73042f24..bf0e7014 100644
--- a/resources/src/mediawiki.special/templates/thumbnail.html
+++ b/resources/src/mediawiki.special/templates/thumbnail.html
@@ -1,6 +1,5 @@
<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>
diff --git a/resources/src/mediawiki.toolbar/toolbar.js b/resources/src/mediawiki.toolbar/toolbar.js
index 70d54ce3..0469cc50 100644
--- a/resources/src/mediawiki.toolbar/toolbar.js
+++ b/resources/src/mediawiki.toolbar/toolbar.js
@@ -174,7 +174,7 @@
$toolbar = $( '#toolbar' );
for ( i = 0; i < queue.length; i++ ) {
- button = queue[i];
+ button = queue[ i ];
if ( $.isArray( button ) ) {
// Forwarded arguments array from mw.toolbar.addButton
insertButton.apply( toolbar, button );
diff --git a/resources/src/mediawiki.ui/components/buttons.less b/resources/src/mediawiki.ui/components/buttons.less
index f88f3ee6..77b3f9d8 100644
--- a/resources/src/mediawiki.ui/components/buttons.less
+++ b/resources/src/mediawiki.ui/components/buttons.less
@@ -47,7 +47,7 @@
zoom: 1;
// Container styling
- .button-colors(#FFF);
+ .button-colors(#FFF, #CCC, #777);
border-radius: @borderRadius;
min-width: 4em;
@@ -135,10 +135,10 @@
// Styleguide 2.1.1.
&.mw-ui-progressive,
&.mw-ui-primary {
- .button-colors(@colorProgressive);
+ .button-colors(@colorProgressive, @colorProgressiveHighlight, @colorProgressiveActive);
&.mw-ui-quiet {
- .button-colors-quiet(@colorProgressive);
+ .button-colors-quiet(@colorProgressive, @colorProgressiveHighlight, @colorProgressiveActive);
}
}
@@ -158,10 +158,10 @@
//
// Styleguide 2.1.2.
&.mw-ui-constructive {
- .button-colors(@colorConstructive);
+ .button-colors(@colorConstructive, @colorConstructiveHighlight, @colorConstructiveActive);
&.mw-ui-quiet {
- .button-colors-quiet(@colorConstructive);
+ .button-colors-quiet(@colorConstructive, @colorConstructiveHighlight, @colorConstructiveActive);
}
}
@@ -180,10 +180,10 @@
//
// Styleguide 2.1.3.
&.mw-ui-destructive {
- .button-colors(@colorDestructive);
+ .button-colors(@colorDestructive, @colorDestructiveHighlight, @colorDestructiveActive);
&.mw-ui-quiet {
- .button-colors-quiet(@colorDestructive);
+ .button-colors-quiet(@colorDestructive, @colorDestructiveHighlight, @colorDestructiveActive);
}
}
@@ -220,7 +220,7 @@
background: transparent;
border: none;
text-shadow: none;
- .button-colors-quiet(@colorButtonText);
+ .button-colors-quiet(@colorButtonText, @colorButtonTextHighlight, @colorButtonTextActive);
&:hover,
&:focus {
diff --git a/resources/src/mediawiki.ui/components/checkbox.less b/resources/src/mediawiki.ui/components/checkbox.less
index 4829f5f6..ac5becb8 100644
--- a/resources/src/mediawiki.ui/components/checkbox.less
+++ b/resources/src/mediawiki.ui/components/checkbox.less
@@ -54,6 +54,9 @@
// 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;
+ // Render "on top of" the label, so that it's still clickable (T98905)
+ z-index: 1;
+ position: relative;
// ensure the invisible checkbox takes up the required width
width: @checkboxSize;
height: @checkboxSize;
diff --git a/resources/src/mediawiki.ui/components/icons.less b/resources/src/mediawiki.ui/components/icons.less
index ad951b08..d9e8c420 100644
--- a/resources/src/mediawiki.ui/components/icons.less
+++ b/resources/src/mediawiki.ui/components/icons.less
@@ -1,13 +1,9 @@
@import "mediawiki.mixins";
-
-// Variables
-@iconSize: 1.4em;
-@gutterWidth: 1em;
+@import "mediawiki.ui/variables";
// Mixins
.mixin-mw-ui-icon-bgimage(@iconSvg, @iconPng) {
&.mw-ui-icon {
- &:after,
&:before {
.background-image-svg(@iconSvg, @iconPng);
}
@@ -42,7 +38,7 @@
//
// Styleguide 6.1.1.
&.mw-ui-icon-element {
- @width: @iconSize + ( 2 * @gutterWidth );
+ @width: @iconSize + ( 2 * @iconGutterWidth );
text-indent: -999px;
overflow: hidden;
@@ -53,11 +49,10 @@
left: 0;
right: 0;
position: absolute;
- margin: 0 @gutterWidth;
+ margin: 0 @iconGutterWidth;
}
}
- &.mw-ui-icon-after:after,
&.mw-ui-icon-before:before,
&.mw-ui-icon-element:before {
background-position: 50% 50%;
@@ -81,27 +76,7 @@
&: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;
+ margin-right: @iconGutterWidth;
}
}
}
-
-// 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/ok.png b/resources/src/mediawiki.ui/components/images/ok.png
deleted file mode 100644
index 1ea6aa2d..00000000
--- a/resources/src/mediawiki.ui/components/images/ok.png
+++ /dev/null
Binary files differ
diff --git a/resources/src/mediawiki.ui/components/images/ok.svg b/resources/src/mediawiki.ui/components/images/ok.svg
deleted file mode 100644
index a3d3058a..00000000
--- a/resources/src/mediawiki.ui/components/images/ok.svg
+++ /dev/null
@@ -1 +0,0 @@
-<?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.widgets/AUTHORS.txt b/resources/src/mediawiki.widgets/AUTHORS.txt
new file mode 100644
index 00000000..10064b24
--- /dev/null
+++ b/resources/src/mediawiki.widgets/AUTHORS.txt
@@ -0,0 +1,10 @@
+Authors (alphabetically)
+
+Alex Monk <krenair@wikimedia.org>
+Bartosz Dziewoński <bdziewonski@wikimedia.org>
+Ed Sanders <esanders@wikimedia.org>
+James D. Forrester <jforrester@wikimedia.org>
+Roan Kattouw <roan@wikimedia.org>
+Sucheta Ghoshal <sghoshal@wikimedia.org>
+Timo Tijhof <timo@wikimedia.org>
+Trevor Parscal <trevor@wikimedia.org>
diff --git a/resources/src/mediawiki.widgets/LICENSE.txt b/resources/src/mediawiki.widgets/LICENSE.txt
new file mode 100644
index 00000000..b03ca801
--- /dev/null
+++ b/resources/src/mediawiki.widgets/LICENSE.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2011-2015 MediaWiki Widgets Team and others under the
+terms of The MIT License (MIT), as follows:
+
+This software consists of voluntary contributions made by many
+individuals (AUTHORS.txt) For exact contribution history, see the
+revision history and logs, available at https://gerrit.wikimedia.org
+
+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/src/mediawiki.widgets/mw.widgets.CalendarWidget.js b/resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.js
new file mode 100644
index 00000000..af83c5f2
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.js
@@ -0,0 +1,558 @@
+/*!
+ * MediaWiki Widgets – CalendarWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+/*global moment */
+( function ( $, mw ) {
+
+ /**
+ * Creates an mw.widgets.CalendarWidget object.
+ *
+ * You will most likely want to use mw.widgets.DateInputWidget instead of CalendarWidget directly.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ * @mixins OO.ui.mixin.TabIndexedElement
+ * @mixins OO.ui.mixin.FloatableElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [precision='day'] Date precision to use, 'day' or 'month'
+ * @cfg {string|null} [date=null] Day or month date (depending on `precision`), in the format
+ * 'YYYY-MM-DD' or 'YYYY-MM'. When null, the calendar will show today's date, but not select
+ * it.
+ */
+ mw.widgets.CalendarWidget = function MWWCalendarWidget( config ) {
+ // Config initialization
+ config = config || {};
+
+ // Parent constructor
+ mw.widgets.CalendarWidget.parent.call( this, config );
+
+ // Mixin constructors
+ OO.ui.mixin.TabIndexedElement.call( this, $.extend( {}, config, { $tabIndexed: this.$element } ) );
+ OO.ui.mixin.FloatableElement.call( this, config );
+
+ // Properties
+ this.precision = config.precision || 'day';
+ // Currently selected date (day or month)
+ this.date = null;
+ // Current UI state (date and precision we're displaying right now)
+ this.moment = null;
+ this.displayLayer = this.getDisplayLayers()[ 0 ]; // 'month', 'year', 'duodecade'
+
+ this.$header = $( '<div>' ).addClass( 'mw-widget-calendarWidget-header' );
+ this.$bodyOuterWrapper = $( '<div>' ).addClass( 'mw-widget-calendarWidget-body-outer-wrapper' );
+ this.$bodyWrapper = $( '<div>' ).addClass( 'mw-widget-calendarWidget-body-wrapper' );
+ this.$body = $( '<div>' ).addClass( 'mw-widget-calendarWidget-body' );
+ this.labelButton = new OO.ui.ButtonWidget( {
+ tabIndex: -1,
+ label: '',
+ framed: false,
+ classes: [ 'mw-widget-calendarWidget-labelButton' ]
+ } );
+ this.upButton = new OO.ui.ButtonWidget( {
+ tabIndex: -1,
+ framed: false,
+ icon: 'collapse',
+ classes: [ 'mw-widget-calendarWidget-upButton' ]
+ } );
+ this.prevButton = new OO.ui.ButtonWidget( {
+ tabIndex: -1,
+ framed: false,
+ icon: 'previous',
+ classes: [ 'mw-widget-calendarWidget-prevButton' ]
+ } );
+ this.nextButton = new OO.ui.ButtonWidget( {
+ tabIndex: -1,
+ framed: false,
+ icon: 'next',
+ classes: [ 'mw-widget-calendarWidget-nextButton' ]
+ } );
+
+ // Events
+ this.labelButton.connect( this, { click: 'onUpButtonClick' } );
+ this.upButton.connect( this, { click: 'onUpButtonClick' } );
+ this.prevButton.connect( this, { click: 'onPrevButtonClick' } );
+ this.nextButton.connect( this, { click: 'onNextButtonClick' } );
+ this.$element.on( {
+ focus: this.onFocus.bind( this ),
+ mousedown: this.onClick.bind( this ),
+ keydown: this.onKeyDown.bind( this )
+ } );
+
+ // Initialization
+ this.$element
+ .addClass( 'mw-widget-calendarWidget' )
+ .append( this.$header, this.$bodyOuterWrapper.append( this.$bodyWrapper.append( this.$body ) ) );
+ this.$header.append(
+ this.prevButton.$element,
+ this.nextButton.$element,
+ this.upButton.$element,
+ this.labelButton.$element
+ );
+ this.setDate( config.date !== undefined ? config.date : null );
+ };
+
+ /* Inheritance */
+
+ OO.inheritClass( mw.widgets.CalendarWidget, OO.ui.Widget );
+ OO.mixinClass( mw.widgets.CalendarWidget, OO.ui.mixin.TabIndexedElement );
+ OO.mixinClass( mw.widgets.CalendarWidget, OO.ui.mixin.FloatableElement );
+
+ /* Events */
+
+ /**
+ * @event change
+ *
+ * A change event is emitted when the chosen date changes.
+ *
+ * @param {string} date Day or month date, in the format 'YYYY-MM-DD' or 'YYYY-MM'
+ */
+
+ /* Methods */
+
+ /**
+ * Get the date format ('YYYY-MM-DD' or 'YYYY-MM', depending on precision), which is used
+ * internally and for dates accepted by #setDate and returned by #getDate.
+ *
+ * @private
+ * @returns {string} Format
+ */
+ mw.widgets.CalendarWidget.prototype.getDateFormat = function () {
+ return {
+ day: 'YYYY-MM-DD',
+ month: 'YYYY-MM'
+ }[ this.precision ];
+ };
+
+ /**
+ * Get the date precision this calendar uses, 'day' or 'month'.
+ *
+ * @private
+ * @returns {string} Precision, 'day' or 'month'
+ */
+ mw.widgets.CalendarWidget.prototype.getPrecision = function () {
+ return this.precision;
+ };
+
+ /**
+ * Get list of possible display layers.
+ *
+ * @private
+ * @returns {string[]} Layers
+ */
+ mw.widgets.CalendarWidget.prototype.getDisplayLayers = function () {
+ return [ 'month', 'year', 'duodecade' ].slice( this.precision === 'month' ? 1 : 0 );
+ };
+
+ /**
+ * Update the calendar.
+ *
+ * @private
+ * @param {string|null} [fade=null] Direction in which to fade out current calendar contents,
+ * 'previous', 'next', 'up' or 'down'; or 'auto', which has the same result as 'previous' or
+ * 'next' depending on whether the current date is later or earlier than the previous.
+ * @returns {string} Format
+ */
+ mw.widgets.CalendarWidget.prototype.updateUI = function ( fade ) {
+ var items, today, selected, currentMonth, currentYear, currentDay, i, needsFade,
+ $bodyWrapper = this.$bodyWrapper;
+
+ if (
+ this.displayLayer === this.previousDisplayLayer &&
+ this.date === this.previousDate &&
+ this.previousMoment &&
+ this.previousMoment.isSame( this.moment, this.precision === 'month' ? 'month' : 'day' )
+ ) {
+ // Already displayed
+ return;
+ }
+
+ if ( fade === 'auto' ) {
+ if ( !this.previousMoment ) {
+ fade = null;
+ } else if ( this.previousMoment.isBefore( this.moment, this.precision === 'month' ? 'month' : 'day' ) ) {
+ fade = 'next';
+ } else if ( this.previousMoment.isAfter( this.moment, this.precision === 'month' ? 'month' : 'day' ) ) {
+ fade = 'previous';
+ } else {
+ fade = null;
+ }
+ }
+
+ items = [];
+ if ( this.$oldBody ) {
+ this.$oldBody.remove();
+ }
+ this.$oldBody = this.$body.addClass( 'mw-widget-calendarWidget-old-body' );
+ // Clone without children
+ this.$body = $( this.$body[ 0 ].cloneNode( false ) )
+ .removeClass( 'mw-widget-calendarWidget-old-body' )
+ .toggleClass( 'mw-widget-calendarWidget-body-month', this.displayLayer === 'month' )
+ .toggleClass( 'mw-widget-calendarWidget-body-year', this.displayLayer === 'year' )
+ .toggleClass( 'mw-widget-calendarWidget-body-duodecade', this.displayLayer === 'duodecade' );
+
+ today = moment();
+ selected = moment( this.getDate(), this.getDateFormat() );
+
+ switch ( this.displayLayer ) {
+ case 'month':
+ this.labelButton.setLabel( this.moment.format( 'MMMM YYYY' ) );
+ this.upButton.toggle( true );
+
+ // First week displayed is the first week spanned by the month, unless it begins on Monday, in
+ // which case first week displayed is the previous week. This makes the calendar "balanced"
+ // and also neatly handles 28-day February sometimes spanning only 4 weeks.
+ currentDay = moment( this.moment ).startOf( 'month' ).subtract( 1, 'day' ).startOf( 'week' );
+
+ // Day-of-week labels. Localisation-independent: works with weeks starting on Saturday, Sunday
+ // or Monday.
+ for ( i = 0; i < 7; i++ ) {
+ items.push(
+ $( '<div>' )
+ .addClass( 'mw-widget-calendarWidget-day-heading' )
+ .text( currentDay.format( 'dd' ) )
+ );
+ currentDay.add( 1, 'day' );
+ }
+ currentDay.subtract( 7, 'days' );
+
+ // Actual calendar month. Always displays 6 weeks, for consistency (months can span 4 to 6
+ // weeks).
+ for ( i = 0; i < 42; i++ ) {
+ items.push(
+ $( '<div>' )
+ .addClass( 'mw-widget-calendarWidget-item mw-widget-calendarWidget-day' )
+ .toggleClass( 'mw-widget-calendarWidget-day-additional', !currentDay.isSame( this.moment, 'month' ) )
+ .toggleClass( 'mw-widget-calendarWidget-day-today', currentDay.isSame( today, 'day' ) )
+ .toggleClass( 'mw-widget-calendarWidget-item-selected', currentDay.isSame( selected, 'day' ) )
+ .text( currentDay.format( 'D' ) )
+ .data( 'date', currentDay.date() )
+ .data( 'month', currentDay.month() )
+ .data( 'year', currentDay.year() )
+ );
+ currentDay.add( 1, 'day' );
+ }
+ break;
+
+ case 'year':
+ this.labelButton.setLabel( this.moment.format( 'YYYY' ) );
+ this.upButton.toggle( true );
+
+ currentMonth = moment( this.moment ).startOf( 'year' );
+ for ( i = 0; i < 12; i++ ) {
+ items.push(
+ $( '<div>' )
+ .addClass( 'mw-widget-calendarWidget-item mw-widget-calendarWidget-month' )
+ .toggleClass( 'mw-widget-calendarWidget-item-selected', currentMonth.isSame( selected, 'month' ) )
+ .text( currentMonth.format( 'MMMM' ) )
+ .data( 'month', currentMonth.month() )
+ );
+ currentMonth.add( 1, 'month' );
+ }
+ // Shuffle the array to display months in columns rather than rows.
+ items = [
+ items[ 0 ], items[ 6 ], // | January | July |
+ items[ 1 ], items[ 7 ], // | February | August |
+ items[ 2 ], items[ 8 ], // | March | September |
+ items[ 3 ], items[ 9 ], // | April | October |
+ items[ 4 ], items[ 10 ], // | May | November |
+ items[ 5 ], items[ 11 ] // | June | December |
+ ];
+ break;
+
+ case 'duodecade':
+ this.labelButton.setLabel( null );
+ this.upButton.toggle( false );
+
+ currentYear = moment( { year: Math.floor( this.moment.year() / 20 ) * 20 } );
+ for ( i = 0; i < 20; i++ ) {
+ items.push(
+ $( '<div>' )
+ .addClass( 'mw-widget-calendarWidget-item mw-widget-calendarWidget-year' )
+ .toggleClass( 'mw-widget-calendarWidget-item-selected', currentYear.isSame( selected, 'year' ) )
+ .text( currentYear.format( 'YYYY' ) )
+ .data( 'year', currentYear.year() )
+ );
+ currentYear.add( 1, 'year' );
+ }
+ break;
+ }
+
+ this.$body.append.apply( this.$body, items );
+
+ $bodyWrapper
+ .removeClass( 'mw-widget-calendarWidget-body-wrapper-fade-up' )
+ .removeClass( 'mw-widget-calendarWidget-body-wrapper-fade-down' )
+ .removeClass( 'mw-widget-calendarWidget-body-wrapper-fade-previous' )
+ .removeClass( 'mw-widget-calendarWidget-body-wrapper-fade-next' );
+
+ needsFade = this.previousDisplayLayer !== this.displayLayer;
+ if ( this.displayLayer === 'month' ) {
+ needsFade = needsFade || !this.moment.isSame( this.previousMoment, 'month' );
+ } else if ( this.displayLayer === 'year' ) {
+ needsFade = needsFade || !this.moment.isSame( this.previousMoment, 'year' );
+ } else if ( this.displayLayer === 'duodecade' ) {
+ needsFade = needsFade || (
+ Math.floor( this.moment.year() / 20 ) * 20 !==
+ Math.floor( this.previousMoment.year() / 20 ) * 20
+ );
+ }
+
+ if ( fade && needsFade ) {
+ this.$oldBody.find( '.mw-widget-calendarWidget-item-selected' )
+ .removeClass( 'mw-widget-calendarWidget-item-selected' );
+ if ( fade === 'previous' || fade === 'up' ) {
+ this.$body.insertBefore( this.$oldBody );
+ } else if ( fade === 'next' || fade === 'down' ) {
+ this.$body.insertAfter( this.$oldBody );
+ }
+ setTimeout( function () {
+ $bodyWrapper.addClass( 'mw-widget-calendarWidget-body-wrapper-fade-' + fade );
+ }.bind( this ), 0 );
+ } else {
+ this.$oldBody.replaceWith( this.$body );
+ }
+
+ this.previousMoment = moment( this.moment );
+ this.previousDisplayLayer = this.displayLayer;
+ this.previousDate = this.date;
+
+ this.$body.on( 'click', this.onBodyClick.bind( this ) );
+ };
+
+ /**
+ * Handle click events on the "up" button, switching to less precise view.
+ *
+ * @private
+ */
+ mw.widgets.CalendarWidget.prototype.onUpButtonClick = function () {
+ var
+ layers = this.getDisplayLayers(),
+ currentLayer = layers.indexOf( this.displayLayer );
+ if ( currentLayer !== layers.length - 1 ) {
+ // One layer up
+ this.displayLayer = layers[ currentLayer + 1 ];
+ this.updateUI( 'up' );
+ } else {
+ this.updateUI();
+ }
+ };
+
+ /**
+ * Handle click events on the "previous" button, switching to previous pane.
+ *
+ * @private
+ */
+ mw.widgets.CalendarWidget.prototype.onPrevButtonClick = function () {
+ switch ( this.displayLayer ) {
+ case 'month':
+ this.moment.subtract( 1, 'month' );
+ break;
+ case 'year':
+ this.moment.subtract( 1, 'year' );
+ break;
+ case 'duodecade':
+ this.moment.subtract( 20, 'years' );
+ break;
+ }
+ this.updateUI( 'previous' );
+ };
+
+ /**
+ * Handle click events on the "next" button, switching to next pane.
+ *
+ * @private
+ */
+ mw.widgets.CalendarWidget.prototype.onNextButtonClick = function () {
+ switch ( this.displayLayer ) {
+ case 'month':
+ this.moment.add( 1, 'month' );
+ break;
+ case 'year':
+ this.moment.add( 1, 'year' );
+ break;
+ case 'duodecade':
+ this.moment.add( 20, 'years' );
+ break;
+ }
+ this.updateUI( 'next' );
+ };
+
+ /**
+ * Handle click events anywhere in the body of the widget, which contains the matrix of days,
+ * months or years to choose. Maybe change the pane or switch to more precise view, depending on
+ * what gets clicked.
+ *
+ * @private
+ */
+ mw.widgets.CalendarWidget.prototype.onBodyClick = function ( e ) {
+ var
+ $target = $( e.target ),
+ layers = this.getDisplayLayers(),
+ currentLayer = layers.indexOf( this.displayLayer );
+ if ( $target.data( 'year' ) !== undefined ) {
+ this.moment.year( $target.data( 'year' ) );
+ }
+ if ( $target.data( 'month' ) !== undefined ) {
+ this.moment.month( $target.data( 'month' ) );
+ }
+ if ( $target.data( 'date' ) !== undefined ) {
+ this.moment.date( $target.data( 'date' ) );
+ }
+ if ( currentLayer === 0 ) {
+ this.setDateFromMoment();
+ this.updateUI( 'auto' );
+ } else {
+ // One layer down
+ this.displayLayer = layers[ currentLayer - 1 ];
+ this.updateUI( 'down' );
+ }
+ };
+
+ /**
+ * Set the date.
+ *
+ * @param {string|null} [date=null] Day or month date, in the format 'YYYY-MM-DD' or 'YYYY-MM'.
+ * When null, the calendar will show today's date, but not select it. When invalid, the date
+ * is not changed.
+ */
+ mw.widgets.CalendarWidget.prototype.setDate = function ( date ) {
+ var mom = date !== null ? moment( date, this.getDateFormat() ) : moment();
+ if ( mom.isValid() ) {
+ this.moment = mom;
+ if ( date !== null ) {
+ this.setDateFromMoment();
+ } else if ( this.date !== null ) {
+ this.date = null;
+ this.emit( 'change', this.date );
+ }
+ this.displayLayer = this.getDisplayLayers()[ 0 ];
+ this.updateUI();
+ }
+ };
+
+ /**
+ * Reset the user interface of this widget to reflect selected date.
+ */
+ mw.widgets.CalendarWidget.prototype.resetUI = function () {
+ this.moment = this.getDate() !== null ? moment( this.getDate(), this.getDateFormat() ) : moment();
+ this.displayLayer = this.getDisplayLayers()[ 0 ];
+ this.updateUI();
+ };
+
+ /**
+ * Set the date from moment object.
+ *
+ * @private
+ */
+ mw.widgets.CalendarWidget.prototype.setDateFromMoment = function () {
+ // Switch to English locale to avoid number formatting. We want the internal value to be
+ // '2015-07-24' and not '٢٠١٥-٠٧-٢٤' even if the UI language is Arabic.
+ var newDate = moment( this.moment ).locale( 'en' ).format( this.getDateFormat() );
+ if ( this.date !== newDate ) {
+ this.date = newDate;
+ this.emit( 'change', this.date );
+ }
+ };
+
+ /**
+ * Get current date, in the format 'YYYY-MM-DD' or 'YYYY-MM', depending on precision. Digits will
+ * not be localised.
+ *
+ * @returns {string|null} Date string
+ */
+ mw.widgets.CalendarWidget.prototype.getDate = function () {
+ return this.date;
+ };
+
+ /**
+ * Handle focus events.
+ *
+ * @private
+ */
+ mw.widgets.CalendarWidget.prototype.onFocus = function () {
+ this.displayLayer = this.getDisplayLayers()[ 0 ];
+ this.updateUI( 'down' );
+ };
+
+ /**
+ * Handle mouse click events.
+ *
+ * @private
+ * @param {jQuery.Event} e Mouse click event
+ */
+ mw.widgets.CalendarWidget.prototype.onClick = function ( e ) {
+ if ( !this.isDisabled() && e.which === 1 ) {
+ // Prevent unintended focussing
+ return false;
+ }
+ };
+
+ /**
+ * Handle key down events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key down event
+ */
+ mw.widgets.CalendarWidget.prototype.onKeyDown = function ( e ) {
+ var
+ /*jshint -W024*/
+ dir = OO.ui.Element.static.getDir( this.$element ),
+ /*jshint +W024*/
+ nextDirectionKey = dir === 'ltr' ? OO.ui.Keys.RIGHT : OO.ui.Keys.LEFT,
+ prevDirectionKey = dir === 'ltr' ? OO.ui.Keys.LEFT : OO.ui.Keys.RIGHT,
+ changed = true;
+
+ if ( !this.isDisabled() ) {
+ switch ( e.which ) {
+ case prevDirectionKey:
+ this.moment.subtract( 1, this.precision === 'month' ? 'month' : 'day' );
+ break;
+ case nextDirectionKey:
+ this.moment.add( 1, this.precision === 'month' ? 'month' : 'day' );
+ break;
+ case OO.ui.Keys.UP:
+ this.moment.subtract( 1, this.precision === 'month' ? 'month' : 'week' );
+ break;
+ case OO.ui.Keys.DOWN:
+ this.moment.add( 1, this.precision === 'month' ? 'month' : 'week' );
+ break;
+ case OO.ui.Keys.PAGEUP:
+ this.moment.subtract( 1, this.precision === 'month' ? 'year' : 'month' );
+ break;
+ case OO.ui.Keys.PAGEDOWN:
+ this.moment.add( 1, this.precision === 'month' ? 'year' : 'month' );
+ break;
+ default:
+ changed = false;
+ break;
+ }
+
+ if ( changed ) {
+ this.displayLayer = this.getDisplayLayers()[ 0 ];
+ this.setDateFromMoment();
+ this.updateUI( 'auto' );
+ return false;
+ }
+ }
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.CalendarWidget.prototype.toggle = function ( visible ) {
+ // Parent method
+ mw.widgets.CalendarWidget.parent.prototype.toggle.call( this, visible );
+
+ if ( this.$floatableContainer ) {
+ this.togglePositioning( this.isVisible() );
+ }
+
+ return this;
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.less b/resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.less
new file mode 100644
index 00000000..9d30eb8a
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.CalendarWidget.less
@@ -0,0 +1,243 @@
+/*!
+ * MediaWiki Widgets – CalendarWidget styles.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+@calendarWidth: 21em;
+@calendarHeight: 14em;
+
+.mw-widget-calendarWidget {
+ width: @calendarWidth;
+}
+
+.mw-widget-calendarWidget-header {
+ position: relative;
+ line-height: 2.5em;
+}
+
+.mw-widget-calendarWidget-header .oo-ui-buttonWidget {
+ margin-right: 0;
+}
+
+.mw-widget-calendarWidget-header .mw-widget-calendarWidget-labelButton {
+ margin: 0 auto;
+ display: block;
+ width: @calendarWidth - 2*3em;
+
+ .oo-ui-buttonElement-button {
+ width: @calendarWidth - 2*3em;
+ text-align: center;
+ }
+}
+
+.mw-widget-calendarWidget-upButton {
+ position: absolute;
+ right: 3em;
+}
+
+.mw-widget-calendarWidget-prevButton {
+ float: left;
+}
+
+.mw-widget-calendarWidget-nextButton {
+ float: right;
+}
+
+.mw-widget-calendarWidget-body-outer-wrapper {
+ clear: both;
+ position: relative;
+ overflow: hidden;
+ // Fit 7 days, 3em each
+ width: @calendarWidth;
+ // Fit 6 weeks + heading line, 2em each
+ height: @calendarHeight;
+}
+
+.mw-widget-calendarWidget-body-wrapper {
+ .mw-widget-calendarWidget-body {
+ display: inline-block;
+ // Fit 7 days, 3em each
+ width: @calendarWidth;
+ // Fit 6 weeks + heading line, 2em each
+ height: @calendarHeight;
+ }
+
+ .mw-widget-calendarWidget-old-body {
+ // background: #fdd;
+ }
+
+ .mw-widget-calendarWidget-body:not(.mw-widget-calendarWidget-old-body):first-child {
+ margin-top: -@calendarHeight;
+ margin-left: -@calendarWidth;
+ }
+
+ .mw-widget-calendarWidget-body:not(.mw-widget-calendarWidget-old-body):last-child {
+ margin-top: 0;
+ margin-left: 0;
+ }
+}
+
+.mw-widget-calendarWidget-body-wrapper-fade-previous {
+ width: @calendarWidth * 2;
+ height: @calendarHeight;
+
+ .mw-widget-calendarWidget-body:first-child {
+ margin-top: 0 !important;
+ margin-left: 0 !important;
+ transition: 0.5s margin-left;
+ }
+}
+
+.mw-widget-calendarWidget-body-wrapper-fade-next {
+ width: @calendarWidth * 2;
+ height: @calendarHeight;
+
+ .mw-widget-calendarWidget-body:first-child {
+ margin-left: -@calendarWidth !important;
+ margin-top: 0 !important;
+ transition: 0.5s margin-left;
+ }
+}
+
+.mw-widget-calendarWidget-body-wrapper-fade-up {
+ width: @calendarWidth;
+ height: @calendarHeight * 2;
+
+ .mw-widget-calendarWidget-body {
+ display: block;
+ }
+
+ .mw-widget-calendarWidget-body:first-child {
+ margin-left: 0 !important;
+ margin-top: 0 !important;
+ transition: 0.5s margin-top;
+ }
+}
+
+.mw-widget-calendarWidget-body-wrapper-fade-down {
+ width: @calendarWidth;
+ height: @calendarHeight * 2;
+
+ .mw-widget-calendarWidget-body {
+ display: block;
+ }
+
+ .mw-widget-calendarWidget-body:first-child {
+ margin-left: 0 !important;
+ margin-top: -@calendarHeight !important;
+ transition: 0.5s margin-top;
+ }
+}
+
+.mw-widget-calendarWidget-day,
+.mw-widget-calendarWidget-day-heading,
+.mw-widget-calendarWidget-month,
+.mw-widget-calendarWidget-year {
+ display: inline-block;
+ vertical-align: middle;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ text-align: center;
+}
+
+.mw-widget-calendarWidget-day,
+.mw-widget-calendarWidget-day-heading {
+ // 7x7 grid
+ width: @calendarWidth / 7;
+ line-height: @calendarHeight / 7;
+ // Don't overlap the hacked-up fake box-shadow border we get when focussed
+ &:nth-child(7n) {
+ width: @calendarWidth / 7 - 0.2em;
+ margin-right: 0.2em;
+ }
+ &:nth-child(7n+1) {
+ width: @calendarWidth / 7 - 0.2em;
+ margin-left: 0.2em;
+ }
+ &:nth-child(42) ~ & {
+ line-height: @calendarHeight / 7 - 0.2em;
+ margin-bottom: 0.2em;
+ }
+}
+
+.mw-widget-calendarWidget-month {
+ // 2x6 grid
+ width: @calendarWidth / 2;
+ line-height: @calendarHeight / 6;
+ // Don't overlap the hacked-up fake box-shadow border we get when focussed
+ &:nth-child(2n) {
+ width: @calendarWidth / 2 - 0.2em;
+ margin-right: 0.2em;
+ }
+ &:nth-child(2n+1) {
+ width: @calendarWidth / 2 - 0.2em;
+ margin-left: 0.2em;
+ }
+ &:nth-child(10) ~ & {
+ line-height: @calendarHeight / 6 - 0.2em;
+ margin-bottom: 0.2em;
+ }
+}
+
+.mw-widget-calendarWidget-year {
+ // 5x4 grid
+ width: @calendarWidth / 5;
+ line-height: @calendarHeight / 4;
+ // Don't overlap the hacked-up fake box-shadow border we get when focussed
+ &:nth-child(5n) {
+ width: @calendarWidth / 5 - 0.2em;
+ margin-right: 0.2em;
+ }
+ &:nth-child(5n+1) {
+ width: @calendarWidth / 5 - 0.2em;
+ margin-left: 0.2em;
+ }
+ &:nth-child(15) ~ & {
+ line-height: @calendarHeight / 4 - 0.2em;
+ margin-bottom: 0.2em;
+ }
+}
+
+.mw-widget-calendarWidget-item {
+ cursor: pointer;
+}
+
+/* Theme-specific */
+.mw-widget-calendarWidget {
+ box-shadow: inset 0 0 0 1px #ccc;
+}
+
+.mw-widget-calendarWidget:focus {
+ outline: none;
+ box-shadow: inset 0 0 0 2px #347bff;
+}
+
+.mw-widget-calendarWidget-day {
+ color: #444;
+ border-radius: 0.1em;
+}
+
+.mw-widget-calendarWidget-day-heading {
+ font-weight: bold;
+ color: #555;
+}
+
+.mw-widget-calendarWidget-day-additional {
+ color: #aaa;
+}
+
+.mw-widget-calendarWidget-day-today {
+ box-shadow: inset 0 0 0 1px #3787fb;
+}
+
+.mw-widget-calendarWidget-item-selected {
+ background-color: #d8e6fe;
+ color: #3787fb;
+}
+
+.mw-widget-calendarWidget-item:hover {
+ background-color: #eee;
+}
diff --git a/resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js b/resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js
new file mode 100644
index 00000000..24b0e72b
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.CategoryCapsuleItemWidget.js
@@ -0,0 +1,189 @@
+/*!
+ * MediaWiki Widgets - CategoryCapsuleItemWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ /**
+ * @class mw.widgets.PageExistenceCache
+ * @private
+ * @param {mw.Api} [api]
+ */
+ function PageExistenceCache( api ) {
+ this.api = api || new mw.Api();
+ this.processExistenceCheckQueueDebounced = OO.ui.debounce( this.processExistenceCheckQueue );
+ this.currentRequest = null;
+ this.existenceCache = {};
+ this.existenceCheckQueue = {};
+ }
+
+ /**
+ * Check for existence of pages in the queue.
+ *
+ * @private
+ */
+ PageExistenceCache.prototype.processExistenceCheckQueue = function () {
+ var queue, titles;
+ if ( this.currentRequest ) {
+ // Don't fire off a million requests at the same time
+ this.currentRequest.always( function () {
+ this.currentRequest = null;
+ this.processExistenceCheckQueueDebounced();
+ }.bind( this ) );
+ return;
+ }
+ queue = this.existenceCheckQueue;
+ this.existenceCheckQueue = {};
+ titles = Object.keys( queue ).filter( function ( title ) {
+ if ( this.existenceCache.hasOwnProperty( title ) ) {
+ queue[ title ].resolve( this.existenceCache[ title ] );
+ }
+ return !this.existenceCache.hasOwnProperty( title );
+ }.bind( this ) );
+ if ( !titles.length ) {
+ return;
+ }
+ this.currentRequest = this.api.get( {
+ action: 'query',
+ prop: [ 'info' ],
+ titles: titles
+ } ).done( function ( response ) {
+ var index, curr, title;
+ for ( index in response.query.pages ) {
+ curr = response.query.pages[ index ];
+ title = new ForeignTitle( curr.title ).getPrefixedText();
+ this.existenceCache[ title ] = curr.missing === undefined;
+ queue[ title ].resolve( this.existenceCache[ title ] );
+ }
+ }.bind( this ) );
+ };
+
+ /**
+ * Register a request to check whether a page exists.
+ *
+ * @private
+ * @param {mw.Title} title
+ * @return {jQuery.Promise} Promise resolved with true if the page exists or false otherwise
+ */
+ PageExistenceCache.prototype.checkPageExistence = function ( title ) {
+ var key = title.getPrefixedText();
+ if ( !this.existenceCheckQueue[ key ] ) {
+ this.existenceCheckQueue[ key ] = $.Deferred();
+ }
+ this.processExistenceCheckQueueDebounced();
+ return this.existenceCheckQueue[ key ].promise();
+ };
+
+ /**
+ * @class mw.widgets.ForeignTitle
+ * @private
+ * @extends mw.Title
+ *
+ * @constructor
+ * @inheritdoc
+ */
+ function ForeignTitle() {
+ ForeignTitle.parent.apply( this, arguments );
+ }
+ OO.inheritClass( ForeignTitle, mw.Title );
+ ForeignTitle.prototype.getNamespacePrefix = function () {
+ // We only need to handle categories here...
+ return 'Category:'; // HACK
+ };
+
+ /**
+ * @class mw.widgets.CategoryCapsuleItemWidget
+ *
+ * Category selector capsule item widget. Extends OO.ui.CapsuleItemWidget with the ability to link
+ * to the given page, and to show its existence status (i.e., whether it is a redlink).
+ *
+ * @uses mw.Api
+ * @extends OO.ui.CapsuleItemWidget
+ *
+ * @constructor
+ * @param {Object} config Configuration options
+ * @cfg {mw.Title} title Page title to use (required)
+ * @cfg {string} [apiUrl] API URL, if not the current wiki's API
+ */
+ mw.widgets.CategoryCapsuleItemWidget = function MWWCategoryCapsuleItemWidget( config ) {
+ // Parent constructor
+ mw.widgets.CategoryCapsuleItemWidget.parent.call( this, $.extend( {
+ data: config.title.getMainText(),
+ label: config.title.getMainText()
+ }, config ) );
+
+ // Properties
+ this.title = config.title;
+ this.apiUrl = config.apiUrl || '';
+ this.$link = $( '<a>' )
+ .text( this.label )
+ .attr( 'target', '_blank' )
+ .on( 'click', function ( e ) {
+ // CapsuleMultiSelectWidget really wants to prevent you from clicking the link, don't let it
+ e.stopPropagation();
+ } );
+
+ // Initialize
+ this.setMissing( false );
+ this.$label.replaceWith( this.$link );
+ this.setLabelElement( this.$link );
+
+ /*jshint -W024*/
+ if ( !this.constructor.static.pageExistenceCaches[ this.apiUrl ] ) {
+ this.constructor.static.pageExistenceCaches[ this.apiUrl ] =
+ new PageExistenceCache( new mw.ForeignApi( this.apiUrl ) );
+ }
+ this.constructor.static.pageExistenceCaches[ this.apiUrl ]
+ .checkPageExistence( new ForeignTitle( this.title.getPrefixedText() ) )
+ .done( function ( exists ) {
+ this.setMissing( !exists );
+ }.bind( this ) );
+ /*jshint +W024*/
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.CategoryCapsuleItemWidget, OO.ui.CapsuleItemWidget );
+
+ /* Static Properties */
+
+ /*jshint -W024*/
+ /**
+ * Map of API URLs to PageExistenceCache objects.
+ *
+ * @static
+ * @inheritable
+ * @property {Object}
+ */
+ mw.widgets.CategoryCapsuleItemWidget.static.pageExistenceCaches = {
+ '': new PageExistenceCache()
+ };
+ /*jshint +W024*/
+
+ /* Methods */
+
+ /**
+ * Update label link href and CSS classes to reflect page existence status.
+ *
+ * @private
+ * @param {boolean} missing Whether the page is missing (does not exist)
+ */
+ mw.widgets.CategoryCapsuleItemWidget.prototype.setMissing = function ( missing ) {
+ var
+ title = new ForeignTitle( this.title.getPrefixedText() ), // HACK
+ prefix = this.apiUrl.replace( '/w/api.php', '' ); // HACK
+
+ if ( !missing ) {
+ this.$link
+ .attr( 'href', prefix + title.getUrl() )
+ .removeClass( 'new' );
+ } else {
+ this.$link
+ .attr( 'href', prefix + title.getUrl( { action: 'edit', redlink: 1 } ) )
+ .addClass( 'new' );
+ }
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.CategorySelector.js b/resources/src/mediawiki.widgets/mw.widgets.CategorySelector.js
new file mode 100644
index 00000000..59f1d507
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.CategorySelector.js
@@ -0,0 +1,378 @@
+/*!
+ * MediaWiki Widgets - CategorySelector class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+ var CSP,
+ NS_CATEGORY = mw.config.get( 'wgNamespaceIds' ).category;
+
+ /**
+ * Category selector widget. Displays an OO.ui.CapsuleMultiSelectWidget
+ * and autocompletes with available categories.
+ *
+ * var selector = new mw.widgets.CategorySelector( {
+ * searchTypes: [
+ * mw.widgets.CategorySelector.SearchType.OpenSearch,
+ * mw.widgets.CategorySelector.SearchType.InternalSearch
+ * ]
+ * } );
+ *
+ * $( '#content' ).append( selector.$element );
+ *
+ * selector.setSearchType( [ mw.widgets.CategorySelector.SearchType.SubCategories ] );
+ *
+ * @class mw.widgets.CategorySelector
+ * @uses mw.Api
+ * @extends OO.ui.CapsuleMultiSelectWidget
+ * @mixins OO.ui.mixin.PendingElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {mw.Api} [api] Instance of mw.Api (or subclass thereof) to use for queries
+ * @cfg {number} [limit=10] Maximum number of results to load
+ * @cfg {mw.widgets.CategorySelector.SearchType[]} [searchTypes=[mw.widgets.CategorySelector.SearchType.OpenSearch]]
+ * Default search API to use when searching.
+ */
+ function CategorySelector( config ) {
+ // Config initialization
+ config = $.extend( {
+ limit: 10,
+ searchTypes: [ CategorySelector.SearchType.OpenSearch ]
+ }, config );
+ this.limit = config.limit;
+ this.searchTypes = config.searchTypes;
+ this.validateSearchTypes();
+
+ // Parent constructor
+ mw.widgets.CategorySelector.parent.call( this, $.extend( true, {}, config, {
+ menu: {
+ filterFromInput: false
+ },
+ // This allows the user to both select non-existent categories, and prevents the selector from
+ // being wiped from #onMenuItemsChange when we change the available options in the dropdown
+ allowArbitrary: true
+ } ) );
+
+ // Mixin constructors
+ OO.ui.mixin.PendingElement.call( this, $.extend( {}, config, { $pending: this.$handle } ) );
+
+ // Event handler to call the autocomplete methods
+ this.$input.on( 'change input cut paste', OO.ui.debounce( this.updateMenuItems.bind( this ), 100 ) );
+
+ // Initialize
+ this.api = config.api || new mw.Api();
+ }
+
+ /* Setup */
+
+ OO.inheritClass( CategorySelector, OO.ui.CapsuleMultiSelectWidget );
+ OO.mixinClass( CategorySelector, OO.ui.mixin.PendingElement );
+ CSP = CategorySelector.prototype;
+
+ /* Methods */
+
+ /**
+ * Gets new items based on the input by calling
+ * {@link #getNewMenuItems getNewItems} and updates the menu
+ * after removing duplicates based on the data value.
+ *
+ * @private
+ * @method
+ */
+ CSP.updateMenuItems = function () {
+ this.getMenu().clearItems();
+ this.getNewMenuItems( this.$input.val() ).then( function ( items ) {
+ var existingItems, filteredItems,
+ menu = this.getMenu();
+
+ // Never show the menu if the input lost focus in the meantime
+ if ( !this.$input.is( ':focus' ) ) {
+ return;
+ }
+
+ // Array of strings of the data of OO.ui.MenuOptionsWidgets
+ existingItems = menu.getItems().map( function ( item ) {
+ return item.data;
+ } );
+
+ // Remove if items' data already exists
+ filteredItems = items.filter( function ( item ) {
+ return existingItems.indexOf( item ) === -1;
+ } );
+
+ // Map to an array of OO.ui.MenuOptionWidgets
+ filteredItems = filteredItems.map( function ( item ) {
+ return new OO.ui.MenuOptionWidget( {
+ data: item,
+ label: item
+ } );
+ } );
+
+ menu.addItems( filteredItems ).toggle( true );
+ }.bind( this ) );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ CSP.clearInput = function () {
+ CategorySelector.parent.prototype.clearInput.call( this );
+ // Abort all pending requests, we won't need their results
+ this.api.abort();
+ };
+
+ /**
+ * Searches for categories based on the input.
+ *
+ * @private
+ * @method
+ * @param {string} input The input used to prefix search categories
+ * @return {jQuery.Promise} Resolves with an array of categories
+ */
+ CSP.getNewMenuItems = function ( input ) {
+ var i,
+ promises = [],
+ deferred = new $.Deferred();
+
+ if ( $.trim( input ) === '' ) {
+ deferred.resolve( [] );
+ return deferred.promise();
+ }
+
+ // Abort all pending requests, we won't need their results
+ this.api.abort();
+ for ( i = 0; i < this.searchTypes.length; i++ ) {
+ promises.push( this.searchCategories( input, this.searchTypes[ i ] ) );
+ }
+
+ this.pushPending();
+
+ $.when.apply( $, promises ).done( function () {
+ var categories, categoryNames,
+ allData = [],
+ dataSets = Array.prototype.slice.apply( arguments );
+
+ // Collect values from all results
+ allData = allData.concat.apply( allData, dataSets );
+
+ // Remove duplicates
+ categories = allData.filter( function ( value, index, self ) {
+ return self.indexOf( value ) === index;
+ } );
+
+ // Get titles
+ categoryNames = categories.map( function ( name ) {
+ return mw.Title.newFromText( name, NS_CATEGORY ).getMainText();
+ } );
+
+ deferred.resolve( categoryNames );
+
+ } ).always( this.popPending.bind( this ) );
+
+ return deferred.promise();
+ };
+
+ /**
+ * @inheritdoc
+ */
+ CSP.createItemWidget = function ( data ) {
+ return new mw.widgets.CategoryCapsuleItemWidget( {
+ apiUrl: this.api.apiUrl || undefined,
+ title: mw.Title.newFromText( data, NS_CATEGORY )
+ } );
+ };
+
+ /**
+ * Validates the values in `this.searchType`.
+ *
+ * @private
+ * @return {boolean}
+ */
+ CSP.validateSearchTypes = function () {
+ var validSearchTypes = false,
+ searchTypeEnumCount = Object.keys( CategorySelector.SearchType ).length;
+
+ // Check if all values are in the SearchType enum
+ validSearchTypes = this.searchTypes.every( function ( searchType ) {
+ return searchType > -1 && searchType < searchTypeEnumCount;
+ } );
+
+ if ( validSearchTypes === false ) {
+ throw new Error( 'Unknown searchType in searchTypes' );
+ }
+
+ // If the searchTypes has CategorySelector.SearchType.SubCategories
+ // it can be the only search type.
+ if ( this.searchTypes.indexOf( CategorySelector.SearchType.SubCategories ) > -1 &&
+ this.searchTypes.length > 1
+ ) {
+ throw new Error( 'Can\'t have additional search types with CategorySelector.SearchType.SubCategories' );
+ }
+
+ // If the searchTypes has CategorySelector.SearchType.ParentCategories
+ // it can be the only search type.
+ if ( this.searchTypes.indexOf( CategorySelector.SearchType.ParentCategories ) > -1 &&
+ this.searchTypes.length > 1
+ ) {
+ throw new Error( 'Can\'t have additional search types with CategorySelector.SearchType.ParentCategories' );
+ }
+
+ return true;
+ };
+
+ /**
+ * Sets and validates the value of `this.searchType`.
+ *
+ * @param {mw.widgets.CategorySelector.SearchType[]} searchTypes
+ */
+ CSP.setSearchTypes = function ( searchTypes ) {
+ this.searchTypes = searchTypes;
+ this.validateSearchTypes();
+ };
+
+ /**
+ * Searches categories based on input and searchType.
+ *
+ * @private
+ * @method
+ * @param {string} input The input used to prefix search categories
+ * @param {mw.widgets.CategorySelector.SearchType} searchType
+ * @return {jQuery.Promise} Resolves with an array of categories
+ */
+ CSP.searchCategories = function ( input, searchType ) {
+ var deferred = new $.Deferred();
+
+ switch ( searchType ) {
+ case CategorySelector.SearchType.OpenSearch:
+ this.api.get( {
+ action: 'opensearch',
+ namespace: NS_CATEGORY,
+ limit: this.limit,
+ search: input
+ } ).done( function ( res ) {
+ var categories = res[ 1 ];
+ deferred.resolve( categories );
+ } ).fail( deferred.reject.bind( deferred ) );
+ break;
+
+ case CategorySelector.SearchType.InternalSearch:
+ this.api.get( {
+ action: 'query',
+ list: 'allpages',
+ apnamespace: NS_CATEGORY,
+ aplimit: this.limit,
+ apfrom: input,
+ apprefix: input
+ } ).done( function ( res ) {
+ var categories = res.query.allpages.map( function ( page ) {
+ return page.title;
+ } );
+ deferred.resolve( categories );
+ } ).fail( deferred.reject.bind( deferred ) );
+ break;
+
+ case CategorySelector.SearchType.Exists:
+ if ( input.indexOf( '|' ) > -1 ) {
+ deferred.resolve( [] );
+ break;
+ }
+
+ this.api.get( {
+ action: 'query',
+ prop: 'info',
+ titles: 'Category:' + input
+ } ).done( function ( res ) {
+ var page,
+ categories = [];
+
+ for ( page in res.query.pages ) {
+ if ( parseInt( page, 10 ) > -1 ) {
+ categories.push( res.query.pages[ page ].title );
+ }
+ }
+
+ deferred.resolve( categories );
+ } ).fail( deferred.reject.bind( deferred ) );
+ break;
+
+ case CategorySelector.SearchType.SubCategories:
+ if ( input.indexOf( '|' ) > -1 ) {
+ deferred.resolve( [] );
+ break;
+ }
+
+ this.api.get( {
+ action: 'query',
+ list: 'categorymembers',
+ cmtype: 'subcat',
+ cmlimit: this.limit,
+ cmtitle: 'Category:' + input
+ } ).done( function ( res ) {
+ var categories = res.query.categorymembers.map( function ( category ) {
+ return category.title;
+ } );
+ deferred.resolve( categories );
+ } ).fail( deferred.reject.bind( deferred ) );
+ break;
+
+ case CategorySelector.SearchType.ParentCategories:
+ if ( input.indexOf( '|' ) > -1 ) {
+ deferred.resolve( [] );
+ break;
+ }
+
+ this.api.get( {
+ action: 'query',
+ prop: 'categories',
+ cllimit: this.limit,
+ titles: 'Category:' + input
+ } ).done( function ( res ) {
+ var page,
+ categories = [];
+
+ for ( page in res.query.pages ) {
+ if ( parseInt( page, 10 ) > -1 ) {
+ if ( $.isArray( res.query.pages[ page ].categories ) ) {
+ categories.push.apply( categories, res.query.pages[ page ].categories.map( function ( category ) {
+ return category.title;
+ } ) );
+ }
+ }
+ }
+
+ deferred.resolve( categories );
+ } ).fail( deferred.reject.bind( deferred ) );
+ break;
+
+ default:
+ throw new Error( 'Unknown searchType' );
+ }
+
+ return deferred.promise();
+ };
+
+ /**
+ * @enum mw.widgets.CategorySelector.SearchType
+ * Types of search available.
+ */
+ CategorySelector.SearchType = {
+ /** Search using action=opensearch */
+ OpenSearch: 0,
+
+ /** Search using action=query */
+ InternalSearch: 1,
+
+ /** Search for existing categories with the exact title */
+ Exists: 2,
+
+ /** Search only subcategories */
+ SubCategories: 3,
+
+ /** Search only parent categories */
+ ParentCategories: 4
+ };
+
+ mw.widgets.CategorySelector = CategorySelector;
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.base.css b/resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.base.css
new file mode 100644
index 00000000..b60883e9
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.base.css
@@ -0,0 +1,26 @@
+/*!
+ * MediaWiki Widgets - base ComplexNamespaceInputWidget styles.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+.mw-widget-complexNamespaceInputWidget .mw-widget-namespaceInputWidget,
+.mw-widget-complexNamespaceInputWidget .oo-ui-fieldLayout {
+ display: inline-block;
+ margin-right: 1em;
+}
+
+/* TODO FieldLayout is not supposed to be used the way we use it here */
+.mw-widget-complexNamespaceInputWidget .oo-ui-fieldLayout {
+ vertical-align: middle;
+ margin-bottom: 0;
+}
+
+.mw-widget-complexNamespaceInputWidget .oo-ui-fieldLayout.oo-ui-fieldLayout-align-inline.oo-ui-labelElement > .oo-ui-fieldLayout-body > .oo-ui-labelElement-label {
+ padding-left: 0.5em;
+}
+
+.mw-widget-complexNamespaceInputWidget .mw-widget-namespaceInputWidget {
+ max-width: 20em;
+}
diff --git a/resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.js b/resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.js
new file mode 100644
index 00000000..f67ed3de
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.ComplexNamespaceInputWidget.js
@@ -0,0 +1,118 @@
+/*!
+ * MediaWiki Widgets - ComplexNamespaceInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ /**
+ * Namespace input widget. Displays a dropdown box with the choice of available namespaces, plus
+ * two checkboxes to include associated namespace or to invert selection.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {Object} namespace Configuration for the NamespaceInputWidget dropdown with list
+ * of namespaces
+ * @cfg {string} namespace.includeAllValue If specified, add a "all namespaces"
+ * option to the dropdown, and use this as the input value for it
+ * @cfg {Object} invert Configuration for the "invert selection" CheckboxInputWidget. If
+ * null, the checkbox will not be generated.
+ * @cfg {Object} associated Configuration for the "include associated namespace"
+ * CheckboxInputWidget. If null, the checkbox will not be generated.
+ * @cfg {Object} invertLabel Configuration for the FieldLayout with label wrapping the
+ * "invert selection" checkbox
+ * @cfg {string} invertLabel.label Label text for the label
+ * @cfg {Object} associatedLabel Configuration for the FieldLayout with label wrapping
+ * the "include associated namespace" checkbox
+ * @cfg {string} associatedLabel.label Label text for the label
+ */
+ mw.widgets.ComplexNamespaceInputWidget = function MwWidgetsComplexNamespaceInputWidget( config ) {
+ // Configuration initialization
+ config = $.extend(
+ {
+ // Config options for nested widgets
+ namespace: {},
+ invert: {},
+ invertLabel: {},
+ associated: {},
+ associatedLabel: {}
+ },
+ config
+ );
+
+ // Parent constructor
+ mw.widgets.ComplexNamespaceInputWidget.parent.call( this, config );
+
+ // Properties
+ this.config = config;
+
+ this.namespace = new mw.widgets.NamespaceInputWidget( config.namespace );
+ if ( config.associated !== null ) {
+ this.associated = new OO.ui.CheckboxInputWidget( $.extend(
+ { value: '1' },
+ config.associated
+ ) );
+ // TODO Should use a LabelWidget? But they don't work like HTML <label>s yet
+ this.associatedLabel = new OO.ui.FieldLayout(
+ this.associated,
+ $.extend(
+ { align: 'inline' },
+ config.associatedLabel
+ )
+ );
+ }
+ if ( config.invert !== null ) {
+ this.invert = new OO.ui.CheckboxInputWidget( $.extend(
+ { value: '1' },
+ config.invert
+ ) );
+ // TODO Should use a LabelWidget? But they don't work like HTML <label>s yet
+ this.invertLabel = new OO.ui.FieldLayout(
+ this.invert,
+ $.extend(
+ { align: 'inline' },
+ config.invertLabel
+ )
+ );
+ }
+
+ // Events
+ this.namespace.connect( this, { change: 'updateCheckboxesState' } );
+
+ // Initialization
+ this.$element
+ .addClass( 'mw-widget-complexNamespaceInputWidget' )
+ .append(
+ this.namespace.$element,
+ this.invert ? this.invertLabel.$element : '',
+ this.associated ? this.associatedLabel.$element : ''
+ );
+ this.updateCheckboxesState();
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.ComplexNamespaceInputWidget, OO.ui.Widget );
+
+ /* Methods */
+
+ /**
+ * Update the disabled state of checkboxes when the value of namespace dropdown changes.
+ *
+ * @private
+ */
+ mw.widgets.ComplexNamespaceInputWidget.prototype.updateCheckboxesState = function () {
+ var disabled = this.namespace.getValue() === this.namespace.allValue;
+ if ( this.invert ) {
+ this.invert.setDisabled( disabled );
+ }
+ if ( this.associated ) {
+ this.associated.setDisabled( disabled );
+ }
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.base.css b/resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.base.css
new file mode 100644
index 00000000..73a50d8f
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.base.css
@@ -0,0 +1,20 @@
+/*!
+ * MediaWiki Widgets - base ComplexTitleInputWidget styles.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+.mw-widget-complexTitleInputWidget .mw-widget-namespaceInputWidget,
+.mw-widget-complexTitleInputWidget .mw-widget-titleInputWidget {
+ display: inline-block;
+}
+
+.mw-widget-complexTitleInputWidget .mw-widget-namespaceInputWidget {
+ max-width: 20em;
+ margin-right: 0.5em;
+}
+
+.mw-widget-complexTitleInputWidget .mw-widget-titleInputWidget {
+ max-width: 29.5em;
+}
diff --git a/resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.js b/resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.js
new file mode 100644
index 00000000..0c6c15e4
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.ComplexTitleInputWidget.js
@@ -0,0 +1,63 @@
+/*!
+ * MediaWiki Widgets - ComplexTitleInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ /**
+ * Like TitleInputWidget, but the namespace has to be input through a separate dropdown field.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {Object} namespace Configuration for the NamespaceInputWidget dropdown with list of
+ * namespaces
+ * @cfg {Object} title Configuration for the TitleInputWidget text field
+ */
+ mw.widgets.ComplexTitleInputWidget = function MwWidgetsComplexTitleInputWidget( config ) {
+ // Parent constructor
+ mw.widgets.ComplexTitleInputWidget.parent.call( this, config );
+
+ // Properties
+ this.namespace = new mw.widgets.NamespaceInputWidget( config.namespace );
+ this.title = new mw.widgets.TitleInputWidget( $.extend(
+ {},
+ config.title,
+ {
+ relative: true,
+ namespace: config.namespace.value || null
+ }
+ ) );
+
+ // Events
+ this.namespace.connect( this, { change: 'updateTitleNamespace' } );
+
+ // Initialization
+ this.$element
+ .addClass( 'mw-widget-complexTitleInputWidget' )
+ .append(
+ this.namespace.$element,
+ this.title.$element
+ );
+ this.updateTitleNamespace();
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.ComplexTitleInputWidget, OO.ui.Widget );
+
+ /* Methods */
+
+ /**
+ * Update the namespace to use for search suggestions of the title when the value of namespace
+ * dropdown changes.
+ */
+ mw.widgets.ComplexTitleInputWidget.prototype.updateTitleNamespace = function () {
+ this.title.setNamespace( Number( this.namespace.getValue() ) );
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.js b/resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.js
new file mode 100644
index 00000000..b1e5151b
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.js
@@ -0,0 +1,629 @@
+/*!
+ * MediaWiki Widgets – DateInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+/*global moment */
+( function ( $, mw ) {
+
+ /**
+ * Creates an mw.widgets.DateInputWidget object.
+ *
+ * @example
+ * // Date input widget showcase
+ * var fieldset = new OO.ui.FieldsetLayout( {
+ * items: [
+ * new OO.ui.FieldLayout(
+ * new mw.widgets.DateInputWidget(),
+ * {
+ * align: 'top',
+ * label: 'Select date'
+ * }
+ * ),
+ * new OO.ui.FieldLayout(
+ * new mw.widgets.DateInputWidget( { precision: 'month' } ),
+ * {
+ * align: 'top',
+ * label: 'Select month'
+ * }
+ * ),
+ * new OO.ui.FieldLayout(
+ * new mw.widgets.DateInputWidget( {
+ * inputFormat: 'DD.MM.YYYY',
+ * displayFormat: 'Do [of] MMMM [anno Domini] YYYY'
+ * } ),
+ * {
+ * align: 'top',
+ * label: 'Select date (custom formats)'
+ * }
+ * )
+ * ]
+ * } );
+ * $( 'body' ).append( fieldset.$element );
+ *
+ * The value is stored in 'YYYY-MM-DD' or 'YYYY-MM' format:
+ *
+ * @example
+ * // Accessing values in a date input widget
+ * var dateInput = new mw.widgets.DateInputWidget();
+ * var $label = $( '<p>' );
+ * $( 'body' ).append( $label, dateInput.$element );
+ * dateInput.on( 'change', function () {
+ * // The value will always be a valid date or empty string, malformed input is ignored
+ * var date = dateInput.getValue();
+ * $label.text( 'Selected date: ' + ( date || '(none)' ) );
+ * } );
+ *
+ * @class
+ * @extends OO.ui.InputWidget
+ * @mixins OO.ui.mixin.IndicatorElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [precision='day'] Date precision to use, 'day' or 'month'
+ * @cfg {string} [value] Day or month date (depending on `precision`), in the format 'YYYY-MM-DD'
+ * or 'YYYY-MM'. If not given or empty string, no date is selected.
+ * @cfg {string} [inputFormat] Date format string to use for the textual input field. Displayed
+ * while the widget is active, and the user can type in a date in this format. Should be short
+ * and easy to type. When not given, defaults to 'YYYY-MM-DD' or 'YYYY-MM', depending on
+ * `precision`.
+ * @cfg {string} [displayFormat] Date format string to use for the clickable label. Displayed
+ * while the widget is inactive. Should be as unambiguous as possible (for example, prefer to
+ * spell out the month, rather than rely on the order), even if that makes it longer. When not
+ * given, the default is language-specific.
+ * @cfg {string} [placeholder] User-visible date format string displayed in the textual input
+ * field when it's empty. Should be the same as `inputFormat`, but translated to the user's
+ * language. When not given, defaults to a translated version of 'YYYY-MM-DD' or 'YYYY-MM',
+ * depending on `precision`.
+ * @cfg {boolean} [required=false] Mark the field as required. Implies `indicator: 'required'`.
+ * @cfg {string} [mustBeAfter] Validates the date to be after this. In the 'YYYY-MM-DD' format.
+ * @cfg {string} [mustBeBefore] Validates the date to be before this. In the 'YYYY-MM-DD' format.
+ * @cfg {jQuery} [$overlay] Render the calendar into a separate layer. This configuration is
+ * useful in cases where the expanded calendar is larger than its container. The specified
+ * overlay layer is usually on top of the container and has a larger area. By default, the
+ * calendar uses relative positioning.
+ */
+ mw.widgets.DateInputWidget = function MWWDateInputWidget( config ) {
+ // Config initialization
+ config = $.extend( { precision: 'day', required: false }, config );
+ if ( config.required ) {
+ if ( config.indicator === undefined ) {
+ config.indicator = 'required';
+ }
+ }
+
+ var placeholder, mustBeAfter, mustBeBefore;
+ if ( config.placeholder ) {
+ placeholder = config.placeholder;
+ } else if ( config.inputFormat ) {
+ // We have no way to display a translated placeholder for custom formats
+ placeholder = '';
+ } else {
+ // Messages: mw-widgets-dateinput-placeholder-day, mw-widgets-dateinput-placeholder-month
+ placeholder = mw.msg( 'mw-widgets-dateinput-placeholder-' + config.precision );
+ }
+
+ // Properties (must be set before parent constructor, which calls #setValue)
+ this.$handle = $( '<div>' );
+ this.label = new OO.ui.LabelWidget();
+ this.textInput = new OO.ui.TextInputWidget( {
+ required: config.required,
+ placeholder: placeholder,
+ validate: this.validateDate.bind( this )
+ } );
+ this.calendar = new mw.widgets.CalendarWidget( {
+ // Can't pass `$floatableContainer: this.$element` here, the latter is not set yet.
+ // Instead we call setFloatableContainer() below.
+ precision: config.precision
+ } );
+ this.inCalendar = 0;
+ this.inTextInput = 0;
+ this.inputFormat = config.inputFormat;
+ this.displayFormat = config.displayFormat;
+ this.required = config.required;
+
+ // Validate and set min and max dates as properties
+ mustBeAfter = moment( config.mustBeAfter, 'YYYY-MM-DD' );
+ mustBeBefore = moment( config.mustBeBefore, 'YYYY-MM-DD' );
+ if (
+ config.mustBeAfter !== undefined &&
+ mustBeAfter.isValid()
+ ) {
+ this.mustBeAfter = mustBeAfter;
+ }
+
+ if (
+ config.mustBeBefore !== undefined &&
+ mustBeBefore.isValid()
+ ) {
+ this.mustBeBefore = mustBeBefore;
+ }
+
+ // Parent constructor
+ mw.widgets.DateInputWidget.parent.call( this, config );
+
+ // Mixin constructors
+ OO.ui.mixin.IndicatorElement.call( this, config );
+
+ // Events
+ this.calendar.connect( this, {
+ change: 'onCalendarChange'
+ } );
+ this.textInput.connect( this, {
+ enter: 'onEnter',
+ change: 'onTextInputChange'
+ } );
+ this.$element.on( {
+ focusout: this.onBlur.bind( this )
+ } );
+ this.calendar.$element.on( {
+ click: this.onCalendarClick.bind( this ),
+ keypress: this.onCalendarKeyPress.bind( this )
+ } );
+ this.$handle.on( {
+ click: this.onClick.bind( this ),
+ keypress: this.onKeyPress.bind( this )
+ } );
+
+ // Initialization
+ // Move 'tabindex' from this.$input (which is invisible) to the visible handle
+ this.setTabIndexedElement( this.$handle );
+ this.$handle
+ .append( this.label.$element, this.$indicator )
+ .addClass( 'mw-widget-dateInputWidget-handle' );
+ this.calendar.$element
+ .addClass( 'mw-widget-dateInputWidget-calendar' );
+ this.$element
+ .addClass( 'mw-widget-dateInputWidget' )
+ .append( this.$handle, this.textInput.$element, this.calendar.$element );
+
+ if ( config.$overlay ) {
+ this.calendar.setFloatableContainer( this.$element );
+ config.$overlay.append( this.calendar.$element );
+
+ // The text input and calendar are not in DOM order, so fix up focus transitions.
+ this.textInput.$input.on( 'keydown', function ( e ) {
+ if ( e.which === OO.ui.Keys.TAB ) {
+ if ( e.shiftKey ) {
+ // Tabbing backward from text input: normal browser behavior
+ $.noop();
+ } else {
+ // Tabbing forward from text input: just focus the calendar
+ this.calendar.$element.focus();
+ return false;
+ }
+ }
+ }.bind( this ) );
+ this.calendar.$element.on( 'keydown', function ( e ) {
+ if ( e.which === OO.ui.Keys.TAB ) {
+ if ( e.shiftKey ) {
+ // Tabbing backward from calendar: just focus the text input
+ this.textInput.$input.focus();
+ return false;
+ } else {
+ // Tabbing forward from calendar: focus the text input, then allow normal browser
+ // behavior to move focus to next focusable after it
+ this.textInput.$input.focus();
+ }
+ }
+ }.bind( this ) );
+ }
+
+ // Set handle label and hide stuff
+ this.updateUI();
+ this.textInput.toggle( false );
+ this.calendar.toggle( false );
+ };
+
+ /* Inheritance */
+
+ OO.inheritClass( mw.widgets.DateInputWidget, OO.ui.InputWidget );
+ OO.mixinClass( mw.widgets.DateInputWidget, OO.ui.mixin.IndicatorElement );
+
+ /* Methods */
+
+ /**
+ * @inheritdoc
+ * @protected
+ */
+ mw.widgets.DateInputWidget.prototype.getInputElement = function () {
+ return $( '<input type="hidden">' );
+ };
+
+ /**
+ * Respond to calendar date change events.
+ *
+ * @private
+ */
+ mw.widgets.DateInputWidget.prototype.onCalendarChange = function () {
+ this.inCalendar++;
+ if ( !this.inTextInput ) {
+ // If this is caused by user typing in the input field, do not set anything.
+ // The value may be invalid (see #onTextInputChange), but displayable on the calendar.
+ this.setValue( this.calendar.getDate() );
+ }
+ this.inCalendar--;
+ };
+
+ /**
+ * Respond to text input value change events.
+ *
+ * @private
+ */
+ mw.widgets.DateInputWidget.prototype.onTextInputChange = function () {
+ var mom,
+ widget = this,
+ value = this.textInput.getValue(),
+ valid = this.isValidDate( value );
+ this.inTextInput++;
+
+ if ( value === '' ) {
+ // No date selected
+ widget.setValue( '' );
+ } else if ( valid ) {
+ // Well-formed date value, parse and set it
+ mom = moment( value, widget.getInputFormat() );
+ // Use English locale to avoid number formatting
+ widget.setValue( mom.locale( 'en' ).format( widget.getInternalFormat() ) );
+ } else {
+ // Not well-formed, but possibly partial? Try updating the calendar, but do not set the
+ // internal value. Generally this only makes sense when 'inputFormat' is little-endian (e.g.
+ // 'YYYY-MM-DD'), but that's hard to check for, and might be difficult to handle the parsing
+ // right for weird formats. So limit this trick to only when we're using the default
+ // 'inputFormat', which is the same as the internal format, 'YYYY-MM-DD'.
+ if ( widget.getInputFormat() === widget.getInternalFormat() ) {
+ widget.calendar.setDate( widget.textInput.getValue() );
+ }
+ }
+ widget.inTextInput--;
+
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.DateInputWidget.prototype.setValue = function ( value ) {
+ var oldValue = this.value;
+
+ if ( !moment( value, this.getInternalFormat() ).isValid() ) {
+ value = '';
+ }
+
+ mw.widgets.DateInputWidget.parent.prototype.setValue.call( this, value );
+
+ if ( this.value !== oldValue ) {
+ this.updateUI();
+ this.setValidityFlag();
+ }
+
+ return this;
+ };
+
+ /**
+ * Handle text input and calendar blur events.
+ *
+ * @private
+ */
+ mw.widgets.DateInputWidget.prototype.onBlur = function () {
+ var widget = this;
+ setTimeout( function () {
+ var $focussed = $( ':focus' );
+ // Deactivate unless the focus moved to something else inside this widget
+ if (
+ !OO.ui.contains( widget.$element[ 0 ], $focussed[ 0 ], true ) &&
+ // Calendar might be in an $overlay
+ !OO.ui.contains( widget.calendar.$element[ 0 ], $focussed[ 0 ], true )
+ ) {
+ widget.deactivate();
+ }
+ }, 0 );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.DateInputWidget.prototype.focus = function () {
+ this.activate();
+ return this;
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.DateInputWidget.prototype.blur = function () {
+ this.deactivate();
+ return this;
+ };
+
+ /**
+ * Update the contents of the label, text input and status of calendar to reflect selected value.
+ *
+ * @private
+ */
+ mw.widgets.DateInputWidget.prototype.updateUI = function () {
+ if ( this.getValue() === '' ) {
+ this.textInput.setValue( '' );
+ this.calendar.setDate( null );
+ this.label.setLabel( mw.msg( 'mw-widgets-dateinput-no-date' ) );
+ this.$element.addClass( 'mw-widget-dateInputWidget-empty' );
+ } else {
+ if ( !this.inTextInput ) {
+ this.textInput.setValue( this.getMoment().format( this.getInputFormat() ) );
+ }
+ if ( !this.inCalendar ) {
+ this.calendar.setDate( this.getValue() );
+ }
+ this.label.setLabel( this.getMoment().format( this.getDisplayFormat() ) );
+ this.$element.removeClass( 'mw-widget-dateInputWidget-empty' );
+ }
+ };
+
+ /**
+ * Deactivate this input field for data entry. Closes the calendar and hides the text field.
+ *
+ * @private
+ */
+ mw.widgets.DateInputWidget.prototype.deactivate = function () {
+ this.$element.removeClass( 'mw-widget-dateInputWidget-active' );
+ this.$handle.show();
+ this.textInput.toggle( false );
+ this.calendar.toggle( false );
+ this.setValidityFlag();
+ };
+
+ /**
+ * Activate this input field for data entry. Opens the calendar and shows the text field.
+ *
+ * @private
+ */
+ mw.widgets.DateInputWidget.prototype.activate = function () {
+ this.calendar.resetUI();
+ this.$element.addClass( 'mw-widget-dateInputWidget-active' );
+ this.$handle.hide();
+ this.textInput.toggle( true );
+ this.calendar.toggle( true );
+
+ this.textInput.$input.focus();
+ };
+
+ /**
+ * Get the date format to be used for handle label when the input is inactive.
+ *
+ * @private
+ * @return {string} Format string
+ */
+ mw.widgets.DateInputWidget.prototype.getDisplayFormat = function () {
+ if ( this.displayFormat !== undefined ) {
+ return this.displayFormat;
+ }
+
+ if ( this.calendar.getPrecision() === 'month' ) {
+ return 'MMMM YYYY';
+ } else {
+ // The formats Moment.js provides:
+ // * ll: Month name, day of month, year
+ // * lll: Month name, day of month, year, time
+ // * llll: Month name, day of month, day of week, year, time
+ //
+ // The format we want:
+ // * ????: Month name, day of month, day of week, year
+ //
+ // We try to construct it as 'llll - (lll - ll)' and hope for the best.
+ // This seems to work well for many languages (maybe even all?).
+
+ var localeData = moment.localeData( moment.locale() ),
+ llll = localeData.longDateFormat( 'llll' ),
+ lll = localeData.longDateFormat( 'lll' ),
+ ll = localeData.longDateFormat( 'll' ),
+ format = llll.replace( lll.replace( ll, '' ), '' );
+
+ return format;
+ }
+ };
+
+ /**
+ * Get the date format to be used for the text field when the input is active.
+ *
+ * @private
+ * @return {string} Format string
+ */
+ mw.widgets.DateInputWidget.prototype.getInputFormat = function () {
+ if ( this.inputFormat !== undefined ) {
+ return this.inputFormat;
+ }
+
+ return {
+ day: 'YYYY-MM-DD',
+ month: 'YYYY-MM'
+ }[ this.calendar.getPrecision() ];
+ };
+
+ /**
+ * Get the date format to be used internally for the value. This is not configurable in any way,
+ * and always either 'YYYY-MM-DD' or 'YYYY-MM'.
+ *
+ * @private
+ * @return {string} Format string
+ */
+ mw.widgets.DateInputWidget.prototype.getInternalFormat = function () {
+ return {
+ day: 'YYYY-MM-DD',
+ month: 'YYYY-MM'
+ }[ this.calendar.getPrecision() ];
+ };
+
+ /**
+ * Get the Moment object for current value.
+ *
+ * @return {Object} Moment object
+ */
+ mw.widgets.DateInputWidget.prototype.getMoment = function () {
+ return moment( this.getValue(), this.getInternalFormat() );
+ };
+
+ /**
+ * Handle mouse click events.
+ *
+ * @private
+ * @param {jQuery.Event} e Mouse click event
+ */
+ mw.widgets.DateInputWidget.prototype.onClick = function ( e ) {
+ if ( !this.isDisabled() && e.which === 1 ) {
+ this.activate();
+ }
+ return false;
+ };
+
+ /**
+ * Handle key press events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key press event
+ */
+ mw.widgets.DateInputWidget.prototype.onKeyPress = function ( e ) {
+ if ( !this.isDisabled() &&
+ ( e.which === OO.ui.Keys.SPACE || e.which === OO.ui.Keys.ENTER )
+ ) {
+ this.activate();
+ return false;
+ }
+ };
+
+ /**
+ * Handle calendar key press events.
+ *
+ * @private
+ * @param {jQuery.Event} e Key press event
+ */
+ mw.widgets.DateInputWidget.prototype.onCalendarKeyPress = function ( e ) {
+ if ( !this.isDisabled() && e.which === OO.ui.Keys.ENTER ) {
+ this.deactivate();
+ this.$handle.focus();
+ return false;
+ }
+ };
+
+ /**
+ * Handle calendar click events.
+ *
+ * @private
+ * @param {jQuery.Event} e Mouse click event
+ */
+ mw.widgets.DateInputWidget.prototype.onCalendarClick = function ( e ) {
+ if (
+ !this.isDisabled() &&
+ e.which === 1 &&
+ $( e.target ).hasClass( 'mw-widget-calendarWidget-day' )
+ ) {
+ this.deactivate();
+ this.$handle.focus();
+ return false;
+ }
+ };
+
+ /**
+ * Handle text input enter events.
+ *
+ * @private
+ */
+ mw.widgets.DateInputWidget.prototype.onEnter = function () {
+ this.deactivate();
+ this.$handle.focus();
+ };
+
+ /**
+ * @private
+ * @param {string} date Date string, to be valid, must be in 'YYYY-MM-DD' or 'YYYY-MM' format or
+ * (unless the field is required) empty
+ * @returns {boolean}
+ */
+ mw.widgets.DateInputWidget.prototype.validateDate = function ( date ) {
+ var isValid;
+ if ( date === '' ) {
+ isValid = !this.required;
+ } else {
+ isValid = this.isValidDate( date ) && this.isInRange( date );
+ }
+ return isValid;
+ };
+
+ /**
+ * @private
+ * @param {string} date Date string, to be valid, must be in 'YYYY-MM-DD' or 'YYYY-MM' format
+ * @returns {boolean}
+ */
+ mw.widgets.DateInputWidget.prototype.isValidDate = function ( date ) {
+ // "Half-strict mode": for example, for the format 'YYYY-MM-DD', 2015-1-3 instead of 2015-01-03
+ // is okay, but 2015-01 isn't, and neither is 2015-01-foo. Use Moment's "fuzzy" mode and check
+ // parsing flags for the details (stoled from implementation of moment#isValid).
+ var
+ mom = moment( date, this.getInputFormat() ),
+ flags = mom.parsingFlags();
+
+ return mom.isValid() && flags.charsLeftOver === 0 && flags.unusedTokens.length === 0;
+ };
+
+ /**
+ * Validates if the date is within the range configured with {@link #cfg-mustBeAfter}
+ * and {@link #cfg-mustBeBefore}.
+ *
+ * @private
+ * @param {string} date Date string, to be valid, must be empty (no date selected) or in
+ * 'YYYY-MM-DD' or 'YYYY-MM' format to be valid
+ * @returns {boolean}
+ */
+ mw.widgets.DateInputWidget.prototype.isInRange = function ( date ) {
+ var momentDate = moment( date, 'YYYY-MM-DD' ),
+ isAfter = ( this.mustBeAfter === undefined || momentDate.isAfter( this.mustBeAfter ) ),
+ isBefore = ( this.mustBeBefore === undefined || momentDate.isBefore( this.mustBeBefore ) );
+
+ return isAfter && isBefore;
+ };
+
+ /**
+ * Get the validity of current value.
+ *
+ * This method returns a promise that resolves if the value is valid and rejects if
+ * it isn't. Uses {@link #validateDate}.
+ *
+ * @return {jQuery.Promise} A promise that resolves if the value is valid, rejects if not.
+ */
+ mw.widgets.DateInputWidget.prototype.getValidity = function () {
+ var isValid = this.validateDate( this.getValue() );
+
+ if ( isValid ) {
+ return $.Deferred().resolve().promise();
+ } else {
+ return $.Deferred().reject().promise();
+ }
+ };
+
+ /**
+ * Sets the 'invalid' flag appropriately.
+ *
+ * @param {boolean} [isValid] Optionally override validation result
+ */
+ mw.widgets.DateInputWidget.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.getValidity().then( function () {
+ setFlag( true );
+ }, function () {
+ setFlag( false );
+ } );
+ }
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.less b/resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.less
new file mode 100644
index 00000000..873cca19
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.DateInputWidget.less
@@ -0,0 +1,134 @@
+/*!
+ * MediaWiki Widgets – DateInputWidget styles.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+.oo-ui-box-sizing( @type: border-box ) {
+ -webkit-box-sizing: @type;
+ -moz-box-sizing: @type;
+ box-sizing: @type;
+}
+
+.oo-ui-unselectable() {
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.oo-ui-inline-spacing( @spacing, @cancelled-spacing: 0 ) {
+ margin-right: @spacing;
+ &:last-child {
+ margin-right: @cancelled-spacing;
+ }
+}
+
+@indicator-size: unit(12 / 16 / 0.8, em);
+
+.mw-widget-dateInputWidget {
+ display: inline-block;
+ position: relative;
+
+ &-handle {
+ width: 100%;
+ display: inline-block;
+ cursor: pointer;
+ position: relative;
+
+ .oo-ui-unselectable();
+ .oo-ui-box-sizing(border-box);
+
+ > .oo-ui-indicatorElement-indicator {
+ display: none;
+ }
+ }
+
+ &.oo-ui-indicatorElement .mw-widget-dateInputWidget-handle > .oo-ui-indicatorElement-indicator {
+ display: block;
+ position: absolute;
+ top: 0;
+ right: 0;
+ height: 100%;
+ }
+
+ &.oo-ui-widget-disabled .mw-widget-dateInputWidget-handle {
+ cursor: default;
+ }
+
+ &-calendar {
+ position: absolute;
+ z-index: 1;
+ }
+
+ // Theme-specific styles
+ width: 21em;
+ margin: 0.25em 0;
+
+ .oo-ui-inline-spacing(0.5em);
+
+ &-handle {
+ padding: 0.5em 1em;
+ border: 1px solid #ccc;
+ border-radius: 0.1em;
+ line-height: 1.275em;
+ background-color: white;
+ }
+
+ &.oo-ui-indicatorElement .mw-widget-dateInputWidget-handle > .oo-ui-indicatorElement-indicator {
+ width: @indicator-size;
+ margin: 0 0.775em;
+ }
+
+ > .oo-ui-textInputWidget input {
+ padding-left: 1em;
+ }
+
+ > .oo-ui-textInputWidget {
+ z-index: 2;
+ }
+
+ &-calendar {
+ background-color: white;
+ margin-top: -2px;
+
+ &:focus {
+ z-index: 3;
+ }
+ }
+
+ &.oo-ui-widget-enabled {
+ .mw-widget-dateInputWidget-handle:hover {
+ border-color: #347bff;
+ }
+ }
+
+ &.oo-ui-widget-disabled {
+ .mw-widget-dateInputWidget-handle {
+ color: #ccc;
+ text-shadow: 0 1px 1px #fff;
+ border-color: #ddd;
+ background-color: #f3f3f3;
+
+ > .oo-ui-indicatorElement-indicator {
+ opacity: 0.2;
+ }
+ }
+
+ }
+
+ &.oo-ui-flaggedElement-invalid {
+ .mw-widget-dateInputWidget-handle {
+ border-color: red;
+ box-shadow: inset 0 0 0 0 red;
+ }
+ }
+
+ &-empty {
+ .mw-widget-dateInputWidget-handle {
+ color: #ccc;
+ }
+ }
+}
diff --git a/resources/src/mediawiki.widgets/mw.widgets.NamespaceInputWidget.js b/resources/src/mediawiki.widgets/mw.widgets.NamespaceInputWidget.js
new file mode 100644
index 00000000..4f1b8749
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.NamespaceInputWidget.js
@@ -0,0 +1,69 @@
+/*!
+ * MediaWiki Widgets - NamespaceInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ /**
+ * Namespace input widget. Displays a dropdown box with the choice of available namespaces.
+ *
+ * @class
+ * @extends OO.ui.DropdownInputWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string|null} [includeAllValue] Value for "all namespaces" option, if any
+ * @cfg {number[]} [exclude] List of namespace numbers to exclude from the selector
+ */
+ mw.widgets.NamespaceInputWidget = function MwWidgetsNamespaceInputWidget( config ) {
+ // Configuration initialization
+ config = $.extend( {}, config, { options: this.getNamespaceDropdownOptions( config ) } );
+
+ // Parent constructor
+ mw.widgets.NamespaceInputWidget.parent.call( this, config );
+
+ // Initialization
+ this.$element.addClass( 'mw-widget-namespaceInputWidget' );
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.NamespaceInputWidget, OO.ui.DropdownInputWidget );
+
+ /* Methods */
+
+ /**
+ * @private
+ */
+ mw.widgets.NamespaceInputWidget.prototype.getNamespaceDropdownOptions = function ( config ) {
+ var options,
+ exclude = config.exclude || [],
+ NS_MAIN = 0;
+
+ options = $.map( mw.config.get( 'wgFormattedNamespaces' ), function ( name, ns ) {
+ if ( ns < NS_MAIN || exclude.indexOf( Number( ns ) ) !== -1 ) {
+ return null; // skip
+ }
+ ns = String( ns );
+ if ( ns === String( NS_MAIN ) ) {
+ name = mw.message( 'blanknamespace' ).text();
+ }
+ return { data: ns, label: name };
+ } ).sort( function ( a, b ) {
+ // wgFormattedNamespaces is an object, and so technically doesn't have to be ordered
+ return a.data - b.data;
+ } );
+
+ if ( config.includeAllValue !== null && config.includeAllValue !== undefined ) {
+ options.unshift( {
+ data: config.includeAllValue,
+ label: mw.message( 'namespacesall' ).text()
+ } );
+ }
+
+ return options;
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css b/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css
new file mode 100644
index 00000000..2c24b2bb
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.css
@@ -0,0 +1,57 @@
+/*!
+ * MediaWiki Widgets - TitleInputWidget styles.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+.mw-widget-titleInputWidget-menu-withImages .mw-widget-titleOptionWidget {
+ -webkit-box-sizing: border-box;
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ min-height: 3.75em;
+ margin-left: 3.75em;
+}
+
+.mw-widget-titleInputWidget-menu-withImages .mw-widget-titleOptionWidget:not(:last-child) {
+ margin-bottom: 1px;
+}
+
+.mw-widget-titleInputWidget-menu-withImages .oo-ui-iconElement .oo-ui-iconElement-icon {
+ display: block;
+ width: 3.75em;
+ height: 3.75em;
+ left: -3.75em;
+ background-color: #ccc;
+ opacity: 0.4;
+}
+
+.mw-widget-titleInputWidget-menu-withImages .oo-ui-iconElement .mw-widget-titleOptionWidget-hasImage {
+ border: 0;
+ background-size: cover;
+ opacity: 1;
+}
+
+.mw-widget-titleInputWidget-menu-withImages .mw-widget-titleOptionWidget .oo-ui-labelElement-label {
+ line-height: 2.8em;
+}
+
+.mw-widget-titleOptionWidget-description {
+ display: none;
+}
+
+.mw-widget-titleInputWidget-menu-withDescriptions .mw-widget-titleOptionWidget .oo-ui-labelElement-label {
+ line-height: 1.5em;
+}
+
+.mw-widget-titleInputWidget-menu-withDescriptions .mw-widget-titleOptionWidget-description {
+ display: block;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+}
+
+.oo-ui-menuOptionWidget:not(.oo-ui-optionWidget-selected) .mw-widget-titleOptionWidget-description,
+.oo-ui-menuOptionWidget.oo-ui-optionWidget-highlighted .mw-widget-titleOptionWidget-description {
+ color: #888;
+}
diff --git a/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js b/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js
new file mode 100644
index 00000000..d5a7abc6
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.TitleInputWidget.js
@@ -0,0 +1,341 @@
+/*!
+ * MediaWiki Widgets - TitleInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ /**
+ * Creates an mw.widgets.TitleInputWidget object.
+ *
+ * @class
+ * @extends OO.ui.TextInputWidget
+ * @mixins OO.ui.mixin.LookupElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {number} [limit=10] Number of results to show
+ * @cfg {number} [namespace] Namespace to prepend to queries
+ * @cfg {boolean} [relative=true] If a namespace is set, return a title relative to it
+ * @cfg {boolean} [suggestions=true] Display search suggestions
+ * @cfg {boolean} [showRedirectTargets=true] Show the targets of redirects
+ * @cfg {boolean} [showRedlink] Show red link to exact match if it doesn't exist
+ * @cfg {boolean} [showImages] Show page images
+ * @cfg {boolean} [showDescriptions] Show page descriptions
+ * @cfg {Object} [cache] Result cache which implements a 'set' method, taking keyed values as an argument
+ */
+ mw.widgets.TitleInputWidget = function MwWidgetsTitleInputWidget( config ) {
+ var widget = this;
+
+ // Config initialization
+ config = $.extend( {
+ maxLength: 255,
+ limit: 10
+ }, config );
+
+ // Parent constructor
+ mw.widgets.TitleInputWidget.parent.call( this, $.extend( {}, config, { autocomplete: false } ) );
+
+ // Mixin constructors
+ OO.ui.mixin.LookupElement.call( this, config );
+
+ // Properties
+ this.limit = config.limit;
+ this.maxLength = config.maxLength;
+ this.namespace = config.namespace !== undefined ? config.namespace : null;
+ this.relative = config.relative !== undefined ? config.relative : true;
+ this.suggestions = config.suggestions !== undefined ? config.suggestions : true;
+ this.showRedirectTargets = config.showRedirectTargets !== false;
+ this.showRedlink = !!config.showRedlink;
+ this.showImages = !!config.showImages;
+ this.showDescriptions = !!config.showDescriptions;
+ this.cache = config.cache;
+
+ // Initialization
+ this.$element.addClass( 'mw-widget-titleInputWidget' );
+ this.lookupMenu.$element.addClass( 'mw-widget-titleInputWidget-menu' );
+ if ( this.showImages ) {
+ this.lookupMenu.$element.addClass( 'mw-widget-titleInputWidget-menu-withImages' );
+ }
+ if ( this.showDescriptions ) {
+ this.lookupMenu.$element.addClass( 'mw-widget-titleInputWidget-menu-withDescriptions' );
+ }
+ this.setLookupsDisabled( !this.suggestions );
+
+ this.interwikiPrefixes = [];
+ this.interwikiPrefixesPromise = new mw.Api().get( {
+ action: 'query',
+ meta: 'siteinfo',
+ siprop: 'interwikimap'
+ } ).done( function ( data ) {
+ $.each( data.query.interwikimap, function ( index, interwiki ) {
+ widget.interwikiPrefixes.push( interwiki.prefix );
+ } );
+ } );
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.TitleInputWidget, OO.ui.TextInputWidget );
+ OO.mixinClass( mw.widgets.TitleInputWidget, OO.ui.mixin.LookupElement );
+
+ /* Methods */
+
+ /**
+ * Get the namespace to prepend to titles in suggestions, if any.
+ *
+ * @return {number|null} Namespace number
+ */
+ mw.widgets.TitleInputWidget.prototype.getNamespace = function () {
+ return this.namespace;
+ };
+
+ /**
+ * Set the namespace to prepend to titles in suggestions, if any.
+ *
+ * @param {number|null} namespace Namespace number
+ */
+ mw.widgets.TitleInputWidget.prototype.setNamespace = function ( namespace ) {
+ this.namespace = namespace;
+ this.lookupCache = {};
+ this.closeLookupMenu();
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.TitleInputWidget.prototype.onLookupMenuItemChoose = function ( item ) {
+ this.closeLookupMenu();
+ this.setLookupsDisabled( true );
+ this.setValue( item.getData() );
+ this.setLookupsDisabled( !this.suggestions );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.TitleInputWidget.prototype.focus = function () {
+ var retval;
+
+ // Prevent programmatic focus from opening the menu
+ this.setLookupsDisabled( true );
+
+ // Parent method
+ retval = mw.widgets.TitleInputWidget.parent.prototype.focus.apply( this, arguments );
+
+ this.setLookupsDisabled( !this.suggestions );
+
+ return retval;
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.TitleInputWidget.prototype.getLookupRequest = function () {
+ var req,
+ widget = this,
+ promiseAbortObject = { abort: function () {
+ // Do nothing. This is just so OOUI doesn't break due to abort being undefined.
+ } };
+
+ if ( mw.Title.newFromText( this.value ) ) {
+ return this.interwikiPrefixesPromise.then( function () {
+ var params, props,
+ interwiki = widget.value.substring( 0, widget.value.indexOf( ':' ) );
+ if (
+ interwiki && interwiki !== '' &&
+ widget.interwikiPrefixes.indexOf( interwiki ) !== -1
+ ) {
+ return $.Deferred().resolve( { query: {
+ pages: [ {
+ title: widget.value
+ } ]
+ } } ).promise( promiseAbortObject );
+ } else {
+ params = {
+ action: 'query',
+ generator: 'prefixsearch',
+ gpssearch: widget.value,
+ gpsnamespace: widget.namespace !== null ? widget.namespace : undefined,
+ gpslimit: widget.limit,
+ ppprop: 'disambiguation'
+ };
+ props = [ 'info', 'pageprops' ];
+ if ( widget.showRedirectTargets ) {
+ params.redirects = '1';
+ }
+ if ( widget.showImages ) {
+ props.push( 'pageimages' );
+ params.pithumbsize = 80;
+ params.pilimit = widget.limit;
+ }
+ if ( widget.showDescriptions ) {
+ props.push( 'pageterms' );
+ params.wbptterms = 'description';
+ }
+ params.prop = props.join( '|' );
+ req = new mw.Api().get( params );
+ promiseAbortObject.abort = req.abort.bind( req ); // todo: ew
+ return req;
+ }
+ } ).promise( promiseAbortObject );
+ } else {
+ // Don't send invalid titles to the API.
+ // Just pretend it returned nothing so we can show the 'invalid title' section
+ return $.Deferred().resolve( {} ).promise( promiseAbortObject );
+ }
+ };
+
+ /**
+ * Get lookup cache item from server response data.
+ *
+ * @method
+ * @param {Mixed} response Response from server
+ */
+ mw.widgets.TitleInputWidget.prototype.getLookupCacheDataFromResponse = function ( response ) {
+ return response.query || {};
+ };
+
+ /**
+ * Get list of menu items from a server response.
+ *
+ * @param {Object} data Query result
+ * @returns {OO.ui.MenuOptionWidget[]} Menu items
+ */
+ mw.widgets.TitleInputWidget.prototype.getLookupMenuOptionsFromData = function ( data ) {
+ var i, len, index, pageExists, pageExistsExact, suggestionPage, page, redirect, redirects,
+ items = [],
+ titles = [],
+ titleObj = mw.Title.newFromText( this.value ),
+ redirectsTo = {},
+ pageData = {};
+
+ if ( data.redirects ) {
+ for ( i = 0, len = data.redirects.length; i < len; i++ ) {
+ redirect = data.redirects[ i ];
+ redirectsTo[ redirect.to ] = redirectsTo[ redirect.to ] || [];
+ redirectsTo[ redirect.to ].push( redirect.from );
+ }
+ }
+
+ for ( index in data.pages ) {
+ suggestionPage = data.pages[ index ];
+ pageData[ suggestionPage.title ] = {
+ missing: suggestionPage.missing !== undefined,
+ redirect: suggestionPage.redirect !== undefined,
+ disambiguation: OO.getProp( suggestionPage, 'pageprops', 'disambiguation' ) !== undefined,
+ imageUrl: OO.getProp( suggestionPage, 'thumbnail', 'source' ),
+ description: OO.getProp( suggestionPage, 'terms', 'description' )
+ };
+
+ // Throw away pages from wrong namespaces. This can happen when 'showRedirectTargets' is true
+ // and we encounter a cross-namespace redirect.
+ if ( this.namespace === null || this.namespace === suggestionPage.ns ) {
+ titles.push( suggestionPage.title );
+ }
+
+ redirects = redirectsTo[ suggestionPage.title ] || [];
+ for ( i = 0, len = redirects.length; i < len; i++ ) {
+ pageData[ redirects[ i ] ] = {
+ missing: false,
+ redirect: true,
+ disambiguation: false,
+ description: mw.msg( 'mw-widgets-titleinput-description-redirect', suggestionPage.title )
+ };
+ titles.push( redirects[ i ] );
+ }
+ }
+
+ // If not found, run value through mw.Title to avoid treating a match as a
+ // mismatch where normalisation would make them matching (bug 48476)
+
+ pageExistsExact = titles.indexOf( this.value ) !== -1;
+ pageExists = pageExistsExact || (
+ titleObj && titles.indexOf( titleObj.getPrefixedText() ) !== -1
+ );
+
+ if ( !pageExists ) {
+ pageData[ this.value ] = {
+ missing: true, redirect: false, disambiguation: false,
+ description: mw.msg( 'mw-widgets-titleinput-description-new-page' )
+ };
+ }
+
+ if ( this.cache ) {
+ this.cache.set( pageData );
+ }
+
+ // Offer the exact text as a suggestion if the page exists
+ if ( pageExists && !pageExistsExact ) {
+ titles.unshift( this.value );
+ }
+ // Offer the exact text as a new page if the title is valid
+ if ( this.showRedlink && !pageExists && titleObj ) {
+ titles.push( this.value );
+ }
+ for ( i = 0, len = titles.length; i < len; i++ ) {
+ page = pageData[ titles[ i ] ] || {};
+ items.push( new mw.widgets.TitleOptionWidget( this.getOptionWidgetData( titles[ i ], page ) ) );
+ }
+
+ return items;
+ };
+
+ /**
+ * Get menu option widget data from the title and page data
+ *
+ * @param {mw.Title} title Title object
+ * @param {Object} data Page data
+ * @return {Object} Data for option widget
+ */
+ mw.widgets.TitleInputWidget.prototype.getOptionWidgetData = function ( title, data ) {
+ var mwTitle = new mw.Title( title );
+ return {
+ data: this.namespace !== null && this.relative
+ ? mwTitle.getRelativeText( this.namespace )
+ : title,
+ title: mwTitle,
+ imageUrl: this.showImages ? data.imageUrl : null,
+ description: this.showDescriptions ? data.description : null,
+ missing: data.missing,
+ redirect: data.redirect,
+ disambiguation: data.disambiguation,
+ query: this.value
+ };
+ };
+
+ /**
+ * Get title object corresponding to given value, or #getValue if not given.
+ *
+ * @param {string} [value] Value to get a title for
+ * @returns {mw.Title|null} Title object, or null if value is invalid
+ */
+ mw.widgets.TitleInputWidget.prototype.getTitle = function ( value ) {
+ var title = value !== undefined ? value : this.getValue(),
+ // mw.Title doesn't handle null well
+ titleObj = mw.Title.newFromText( title, this.namespace !== null ? this.namespace : undefined );
+
+ return titleObj;
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.TitleInputWidget.prototype.cleanUpValue = function ( value ) {
+ var widget = this;
+ value = mw.widgets.TitleInputWidget.parent.prototype.cleanUpValue.call( this, value );
+ return $.trimByteLength( this.value, value, this.maxLength, function ( value ) {
+ var title = widget.getTitle( value );
+ return title ? title.getMain() : value;
+ } ).newVal;
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.TitleInputWidget.prototype.isValid = function () {
+ return $.Deferred().resolve( !!this.getTitle() ).promise();
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js b/resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js
new file mode 100644
index 00000000..ec0c9357
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.TitleOptionWidget.js
@@ -0,0 +1,82 @@
+/*!
+ * MediaWiki Widgets - TitleOptionWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ /**
+ * Creates a mw.widgets.TitleOptionWidget object.
+ *
+ * @class
+ * @extends OO.ui.MenuOptionWidget
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {string} [data] Label to display
+ * @cfg {mw.Title} [title] Page title object
+ * @cfg {string} [imageUrl] Thumbnail image URL with URL encoding
+ * @cfg {string} [description] Page description
+ * @cfg {boolean} [missing] Page doesn't exist
+ * @cfg {boolean} [redirect] Page is a redirect
+ * @cfg {boolean} [disambiguation] Page is a disambiguation page
+ * @cfg {string} [query] Matching query string
+ */
+ mw.widgets.TitleOptionWidget = function MwWidgetsTitleOptionWidget( config ) {
+ var icon;
+
+ if ( config.missing ) {
+ icon = 'page-not-found';
+ } else if ( config.redirect ) {
+ icon = 'page-redirect';
+ } else if ( config.disambiguation ) {
+ icon = 'page-disambiguation';
+ } else {
+ icon = 'page-existing';
+ }
+
+ // Config initialization
+ config = $.extend( {
+ icon: icon,
+ label: config.data,
+ href: config.title.getUrl(),
+ autoFitLabel: false
+ }, config );
+
+ // Parent constructor
+ mw.widgets.TitleOptionWidget.parent.call( this, config );
+
+ // Initialization
+ this.$label.wrap( '<a>' );
+ this.$link = this.$label.parent();
+ this.$link.attr( 'href', config.href );
+ this.$element.addClass( 'mw-widget-titleOptionWidget' );
+
+ // Highlight matching parts of link suggestion
+ this.$label.autoEllipsis( { hasSpan: false, tooltip: true, matchText: config.query } );
+
+ if ( config.missing ) {
+ this.$link.addClass( 'new' );
+ }
+
+ if ( config.imageUrl ) {
+ this.$icon
+ .addClass( 'mw-widget-titleOptionWidget-hasImage' )
+ .css( 'background-image', 'url(' + config.imageUrl + ')' );
+ }
+
+ if ( config.description ) {
+ this.$element.append(
+ $( '<span>' )
+ .addClass( 'mw-widget-titleOptionWidget-description' )
+ .text( config.description )
+ );
+ }
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.TitleOptionWidget, OO.ui.MenuOptionWidget );
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.widgets/mw.widgets.UserInputWidget.js b/resources/src/mediawiki.widgets/mw.widgets.UserInputWidget.js
new file mode 100644
index 00000000..0d0fb735
--- /dev/null
+++ b/resources/src/mediawiki.widgets/mw.widgets.UserInputWidget.js
@@ -0,0 +1,119 @@
+/*!
+ * MediaWiki Widgets - UserInputWidget class.
+ *
+ * @copyright 2011-2015 MediaWiki Widgets Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+( function ( $, mw ) {
+
+ /**
+ * Creates a mw.widgets.UserInputWidget object.
+ *
+ * @class
+ * @extends OO.ui.TextInputWidget
+ * @mixins OO.ui.mixin.LookupElement
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ * @cfg {number} [limit=10] Number of results to show
+ */
+ mw.widgets.UserInputWidget = function MwWidgetsUserInputWidget( config ) {
+ // Config initialization
+ config = config || {};
+
+ // Parent constructor
+ mw.widgets.UserInputWidget.parent.call( this, $.extend( {}, config, { autocomplete: false } ) );
+
+ // Mixin constructors
+ OO.ui.mixin.LookupElement.call( this, config );
+
+ // Properties
+ this.limit = config.limit || 10;
+
+ // Initialization
+ this.$element.addClass( 'mw-widget-userInputWidget' );
+ this.lookupMenu.$element.addClass( 'mw-widget-userInputWidget-menu' );
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.widgets.UserInputWidget, OO.ui.TextInputWidget );
+ OO.mixinClass( mw.widgets.UserInputWidget, OO.ui.mixin.LookupElement );
+
+ /* Methods */
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.UserInputWidget.prototype.onLookupMenuItemChoose = function ( item ) {
+ this.closeLookupMenu();
+ this.setLookupsDisabled( true );
+ this.setValue( item.getData() );
+ this.setLookupsDisabled( false );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.UserInputWidget.prototype.focus = function () {
+ var retval;
+
+ // Prevent programmatic focus from opening the menu
+ this.setLookupsDisabled( true );
+
+ // Parent method
+ retval = mw.widgets.UserInputWidget.parent.prototype.focus.apply( this, arguments );
+
+ this.setLookupsDisabled( false );
+
+ return retval;
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.widgets.UserInputWidget.prototype.getLookupRequest = function () {
+ var inputValue = this.value;
+
+ return new mw.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: inputValue[ 0 ].toUpperCase() + inputValue.slice( 1 ),
+ aulimit: this.limit
+ } );
+ };
+
+ /**
+ * Get lookup cache item from server response data.
+ *
+ * @method
+ * @param {Mixed} response Response from server
+ */
+ mw.widgets.UserInputWidget.prototype.getLookupCacheDataFromResponse = function ( response ) {
+ return response.query.allusers || {};
+ };
+
+ /**
+ * Get list of menu items from a server response.
+ *
+ * @param {Object} data Query result
+ * @returns {OO.ui.MenuOptionWidget[]} Menu items
+ */
+ mw.widgets.UserInputWidget.prototype.getLookupMenuOptionsFromData = function ( data ) {
+ var len, i, user,
+ items = [];
+
+ for ( i = 0, len = data.length; i < len; i++ ) {
+ user = data[ i ] || {};
+ items.push( new OO.ui.MenuOptionWidget( {
+ label: user.name,
+ data: user.name
+ } ) );
+ }
+
+ return items;
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki.legacy/images/feed-icon.png b/resources/src/mediawiki/images/feed-icon.png
index 00f49f6c..00f49f6c 100644
--- a/resources/src/mediawiki.legacy/images/feed-icon.png
+++ b/resources/src/mediawiki/images/feed-icon.png
Binary files differ
diff --git a/resources/src/mediawiki.legacy/images/feed-icon.svg b/resources/src/mediawiki/images/feed-icon.svg
index 6e5f570a..6e5f570a 100644
--- a/resources/src/mediawiki.legacy/images/feed-icon.svg
+++ b/resources/src/mediawiki/images/feed-icon.svg
diff --git a/resources/src/mediawiki.legacy/images/question.png b/resources/src/mediawiki/images/question.png
index f7405d26..f7405d26 100644
--- a/resources/src/mediawiki.legacy/images/question.png
+++ b/resources/src/mediawiki/images/question.png
Binary files differ
diff --git a/resources/src/mediawiki.legacy/images/question.svg b/resources/src/mediawiki/images/question.svg
index 98fbe8dd..98fbe8dd 100644
--- a/resources/src/mediawiki.legacy/images/question.svg
+++ b/resources/src/mediawiki/images/question.svg
diff --git a/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.css b/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.css
new file mode 100644
index 00000000..41435208
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.css
@@ -0,0 +1,5 @@
+.mw-foreignStructuredUpload-bookletLayout-license {
+ font-size: 90%;
+ line-height: 1.4em;
+ color: #555;
+}
diff --git a/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.js b/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.js
new file mode 100644
index 00000000..86fb91bc
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.BookletLayout.js
@@ -0,0 +1,247 @@
+/*global moment */
+( function ( $, mw ) {
+
+ /**
+ * mw.ForeignStructuredUpload.BookletLayout encapsulates the process
+ * of uploading a file to MediaWiki using the mw.ForeignStructuredUpload model.
+ *
+ * var uploadDialog = new mw.Upload.Dialog( {
+ * bookletClass: mw.ForeignStructuredUpload.BookletLayout,
+ * booklet: {
+ * target: 'local'
+ * }
+ * } );
+ * var windowManager = new OO.ui.WindowManager();
+ * $( 'body' ).append( windowManager.$element );
+ * windowManager.addWindows( [ uploadDialog ] );
+ *
+ * @class mw.ForeignStructuredUpload.BookletLayout
+ * @uses mw.ForeignStructuredUpload
+ * @extends mw.Upload.BookletLayout
+ * @cfg {string} [target] Used to choose the target repository.
+ * If nothing is passed, the {@link mw.ForeignUpload#property-target default} is used.
+ */
+ mw.ForeignStructuredUpload.BookletLayout = function ( config ) {
+ config = config || {};
+ // Parent constructor
+ mw.ForeignStructuredUpload.BookletLayout.parent.call( this, config );
+
+ this.target = config.target;
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.ForeignStructuredUpload.BookletLayout, mw.Upload.BookletLayout );
+
+ /* Uploading */
+
+ /**
+ * @inheritdoc
+ */
+ mw.ForeignStructuredUpload.BookletLayout.prototype.initialize = function () {
+ mw.ForeignStructuredUpload.BookletLayout.parent.prototype.initialize.call( this );
+ // Point the CategorySelector to the right wiki as soon as we know what the right wiki is
+ this.upload.apiPromise.done( function ( api ) {
+ // If this is a ForeignApi, it will have a apiUrl, otherwise we don't need to do anything
+ if ( api.apiUrl ) {
+ // Can't reuse the same object, CategorySelector calls #abort on its mw.Api instance
+ this.categoriesWidget.api = new mw.ForeignApi( api.apiUrl );
+ }
+ }.bind( this ) );
+ };
+
+ /**
+ * Returns a {@link mw.ForeignStructuredUpload mw.ForeignStructuredUpload}
+ * with the {@link #cfg-target target} specified in config.
+ *
+ * @protected
+ * @return {mw.Upload}
+ */
+ mw.ForeignStructuredUpload.BookletLayout.prototype.createUpload = function () {
+ return new mw.ForeignStructuredUpload( this.target );
+ };
+
+ /* Form renderers */
+
+ /**
+ * @inheritdoc
+ */
+ mw.ForeignStructuredUpload.BookletLayout.prototype.renderUploadForm = function () {
+ var fieldset, $ownWorkMessage, $notOwnWorkMessage,
+ ownWorkMessage, notOwnWorkMessage, notOwnWorkLocal,
+ validTargets = mw.config.get( 'wgForeignUploadTargets' ),
+ target = this.target || validTargets[ 0 ] || 'local',
+ layout = this;
+
+ // foreign-structured-upload-form-label-own-work-message-local
+ // foreign-structured-upload-form-label-own-work-message-shared
+ ownWorkMessage = mw.message( 'foreign-structured-upload-form-label-own-work-message-' + target );
+ // foreign-structured-upload-form-label-not-own-work-message-local
+ // foreign-structured-upload-form-label-not-own-work-message-shared
+ notOwnWorkMessage = mw.message( 'foreign-structured-upload-form-label-not-own-work-message-' + target );
+ // foreign-structured-upload-form-label-not-own-work-local-local
+ // foreign-structured-upload-form-label-not-own-work-local-shared
+ notOwnWorkLocal = mw.message( 'foreign-structured-upload-form-label-not-own-work-local-' + target );
+
+ if ( !ownWorkMessage.exists() ) {
+ ownWorkMessage = mw.message( 'foreign-structured-upload-form-label-own-work-message-default' );
+ }
+ if ( !notOwnWorkMessage.exists() ) {
+ notOwnWorkMessage = mw.message( 'foreign-structured-upload-form-label-not-own-work-message-default' );
+ }
+ if ( !notOwnWorkLocal.exists() ) {
+ notOwnWorkLocal = mw.message( 'foreign-structured-upload-form-label-not-own-work-local-default' );
+ }
+
+ $ownWorkMessage = $( '<p>' ).html( ownWorkMessage.parse() )
+ .addClass( 'mw-foreignStructuredUpload-bookletLayout-license' );
+ $notOwnWorkMessage = $( '<div>' ).append(
+ $( '<p>' ).html( notOwnWorkMessage.parse() ),
+ $( '<p>' ).html( notOwnWorkLocal.parse() )
+ );
+ $ownWorkMessage.add( $notOwnWorkMessage ).find( 'a' ).attr( 'target', '_blank' );
+
+ this.selectFileWidget = new OO.ui.SelectFileWidget();
+ this.messageLabel = new OO.ui.LabelWidget( {
+ label: $notOwnWorkMessage
+ } );
+ this.ownWorkCheckbox = new OO.ui.CheckboxInputWidget().on( 'change', function ( on ) {
+ layout.messageLabel.toggle( !on );
+ } );
+
+ fieldset = new OO.ui.FieldsetLayout();
+ fieldset.addItems( [
+ new OO.ui.FieldLayout( this.selectFileWidget, {
+ align: 'top',
+ label: mw.msg( 'upload-form-label-select-file' )
+ } ),
+ new OO.ui.FieldLayout( this.ownWorkCheckbox, {
+ align: 'inline',
+ label: $( '<div>' ).append(
+ $( '<p>' ).text( mw.msg( 'foreign-structured-upload-form-label-own-work' ) ),
+ $ownWorkMessage
+ )
+ } ),
+ new OO.ui.FieldLayout( this.messageLabel, {
+ align: 'top'
+ } )
+ ] );
+ this.uploadForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
+
+ // Validation
+ this.selectFileWidget.on( 'change', this.onUploadFormChange.bind( this ) );
+ this.ownWorkCheckbox.on( 'change', this.onUploadFormChange.bind( this ) );
+
+ return this.uploadForm;
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.ForeignStructuredUpload.BookletLayout.prototype.onUploadFormChange = function () {
+ var file = this.selectFileWidget.getValue(),
+ ownWork = this.ownWorkCheckbox.isSelected(),
+ valid = !!file && ownWork;
+ this.emit( 'uploadValid', valid );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.ForeignStructuredUpload.BookletLayout.prototype.renderInfoForm = function () {
+ var fieldset;
+
+ this.filenameWidget = new OO.ui.TextInputWidget( {
+ required: true,
+ validate: /.+/
+ } );
+ this.descriptionWidget = new OO.ui.TextInputWidget( {
+ required: true,
+ validate: /.+/,
+ multiline: true,
+ autosize: true
+ } );
+ this.dateWidget = new mw.widgets.DateInputWidget( {
+ $overlay: this.$overlay,
+ required: true,
+ mustBeBefore: moment().add( 1, 'day' ).locale( 'en' ).format( 'YYYY-MM-DD' ) // Tomorrow
+ } );
+ this.categoriesWidget = new mw.widgets.CategorySelector( {
+ // Can't be done here because we don't know the target wiki yet... done in #initialize.
+ // api: new mw.ForeignApi( ... ),
+ $overlay: this.$overlay
+ } );
+
+ fieldset = new OO.ui.FieldsetLayout( {
+ label: mw.msg( 'upload-form-label-infoform-title' )
+ } );
+ fieldset.addItems( [
+ new OO.ui.FieldLayout( this.filenameWidget, {
+ label: mw.msg( 'upload-form-label-infoform-name' ),
+ align: 'top'
+ } ),
+ new OO.ui.FieldLayout( this.descriptionWidget, {
+ label: mw.msg( 'upload-form-label-infoform-description' ),
+ align: 'top'
+ } ),
+ new OO.ui.FieldLayout( this.categoriesWidget, {
+ label: mw.msg( 'foreign-structured-upload-form-label-infoform-categories' ),
+ align: 'top'
+ } ),
+ new OO.ui.FieldLayout( this.dateWidget, {
+ label: mw.msg( 'foreign-structured-upload-form-label-infoform-date' ),
+ align: 'top'
+ } )
+ ] );
+ this.infoForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
+
+ // Validation
+ this.filenameWidget.on( 'change', this.onInfoFormChange.bind( this ) );
+ this.descriptionWidget.on( 'change', this.onInfoFormChange.bind( this ) );
+ this.dateWidget.on( 'change', this.onInfoFormChange.bind( this ) );
+
+ return this.infoForm;
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.ForeignStructuredUpload.BookletLayout.prototype.onInfoFormChange = function () {
+ var layout = this;
+ $.when(
+ this.filenameWidget.getValidity(),
+ this.descriptionWidget.getValidity(),
+ this.dateWidget.getValidity()
+ ).done( function () {
+ layout.emit( 'infoValid', true );
+ } ).fail( function () {
+ layout.emit( 'infoValid', false );
+ } );
+ };
+
+ /* Getters */
+
+ /**
+ * @inheritdoc
+ */
+ mw.ForeignStructuredUpload.BookletLayout.prototype.getText = function () {
+ this.upload.addDescription( 'en', this.descriptionWidget.getValue() );
+ this.upload.setDate( this.dateWidget.getValue() );
+ this.upload.addCategories( this.categoriesWidget.getItemsData() );
+ return this.upload.getText();
+ };
+
+ /* Setters */
+
+ /**
+ * @inheritdoc
+ */
+ mw.ForeignStructuredUpload.BookletLayout.prototype.clear = function () {
+ mw.ForeignStructuredUpload.BookletLayout.parent.prototype.clear.call( this );
+
+ this.ownWorkCheckbox.setSelected( false );
+ this.categoriesWidget.setItemsFromData( [] );
+ this.dateWidget.setValue( '' ).setValidityFlag( true );
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.js b/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.js
new file mode 100644
index 00000000..dd28ddd4
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.ForeignStructuredUpload.js
@@ -0,0 +1,184 @@
+( function ( mw, OO ) {
+ /**
+ * @class mw.ForeignStructuredUpload
+ * @extends mw.ForeignUpload
+ *
+ * Used to represent an upload in progress on the frontend.
+ *
+ * This subclass will upload to a wiki using a structured metadata
+ * system similar to (or identical to) the one on Wikimedia Commons.
+ *
+ * See <https://commons.wikimedia.org/wiki/Commons:Structured_data> for
+ * a more detailed description of how that system works.
+ *
+ * **TODO: This currently only supports uploads under CC-BY-SA 4.0,
+ * and should really have support for more licenses.**
+ *
+ * @inheritdoc
+ */
+ function ForeignStructuredUpload( target, apiconfig ) {
+ this.date = undefined;
+ this.descriptions = [];
+ this.categories = [];
+
+ mw.ForeignUpload.call( this, target, apiconfig );
+ }
+
+ OO.inheritClass( ForeignStructuredUpload, mw.ForeignUpload );
+
+ /**
+ * Add categories to the upload.
+ *
+ * @param {string[]} categories Array of categories to which this upload will be added.
+ */
+ ForeignStructuredUpload.prototype.addCategories = function ( categories ) {
+ var i, category;
+
+ for ( i = 0; i < categories.length; i++ ) {
+ category = categories[ i ];
+ this.categories.push( category );
+ }
+ };
+
+ /**
+ * Add a description to the upload.
+ *
+ * @param {string} language The language code for the description's language. Must have a template on the target wiki to work properly.
+ * @param {string} description The description of the file.
+ */
+ ForeignStructuredUpload.prototype.addDescription = function ( language, description ) {
+ this.descriptions.push( {
+ language: language,
+ text: description
+ } );
+ };
+
+ /**
+ * Set the date of creation for the upload.
+ *
+ * @param {Date} date
+ */
+ ForeignStructuredUpload.prototype.setDate = function ( date ) {
+ this.date = date;
+ };
+
+ /**
+ * Get the text of the file page, to be created on upload. Brings together
+ * several different pieces of information to create useful text.
+ *
+ * @return {string}
+ */
+ ForeignStructuredUpload.prototype.getText = function () {
+ return (
+ '{{' +
+ this.getTemplateName() +
+ '\n|description=' +
+ this.getDescriptions() +
+ '\n|date=' +
+ this.getDate() +
+ '\n|source=' +
+ this.getSource() +
+ '\n|author=' +
+ this.getUser() +
+ '\n}}\n\n' +
+ this.getLicense() +
+ '\n\n' +
+ this.getCategories()
+ );
+ };
+
+ /**
+ * Gets the wikitext for the creation date of this upload.
+ *
+ * @private
+ * @return {string}
+ */
+ ForeignStructuredUpload.prototype.getDate = function () {
+ if ( !this.date ) {
+ return '';
+ }
+
+ return this.date.toString();
+ };
+
+ /**
+ * Gets the name of the template to use for creating the file metadata.
+ * Override in subclasses for other templates.
+ *
+ * @private
+ * @return {string}
+ */
+ ForeignStructuredUpload.prototype.getTemplateName = function () {
+ return 'Information';
+ };
+
+ /**
+ * Fetches the wikitext for any descriptions that have been added
+ * to the upload.
+ *
+ * @private
+ * @return {string}
+ */
+ ForeignStructuredUpload.prototype.getDescriptions = function () {
+ var i, desc, templateCalls = [];
+
+ for ( i = 0; i < this.descriptions.length; i++ ) {
+ desc = this.descriptions[ i ];
+ templateCalls.push( '{{' + desc.language + '|' + desc.text + '}}' );
+ }
+
+ return templateCalls.join( '\n' );
+ };
+
+ /**
+ * Fetches the wikitext for the categories to which the upload will
+ * be added.
+ *
+ * @private
+ * @return {string}
+ */
+ ForeignStructuredUpload.prototype.getCategories = function () {
+ var i, cat, categoryLinks = [];
+
+ for ( i = 0; i < this.categories.length; i++ ) {
+ cat = this.categories[ i ];
+ categoryLinks.push( '[[Category:' + cat + ']]' );
+ }
+
+ return categoryLinks.join( '\n' );
+ };
+
+ /**
+ * Gets the wikitext for the license of the upload.
+ *
+ * @private
+ * @return {string}
+ */
+ ForeignStructuredUpload.prototype.getLicense = function () {
+ // Make sure this matches the messages for different targets in
+ // mw.ForeignStructuredUpload.BookletLayout.prototype.renderUploadForm
+ return this.target === 'shared' ? '{{self|cc-by-sa-4.0}}' : '';
+ };
+
+ /**
+ * Get the source. This should be some sort of localised text for "Own work".
+ *
+ * @private
+ * @return {string}
+ */
+ ForeignStructuredUpload.prototype.getSource = function () {
+ return '{{own}}';
+ };
+
+ /**
+ * Get the username.
+ *
+ * @private
+ * @return {string}
+ */
+ ForeignStructuredUpload.prototype.getUser = function () {
+ return mw.config.get( 'wgUserName' );
+ };
+
+ mw.ForeignStructuredUpload = ForeignStructuredUpload;
+}( mediaWiki, OO ) );
diff --git a/resources/src/mediawiki/mediawiki.ForeignUpload.js b/resources/src/mediawiki/mediawiki.ForeignUpload.js
new file mode 100644
index 00000000..61fb59f6
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.ForeignUpload.js
@@ -0,0 +1,135 @@
+( function ( mw, OO, $ ) {
+ /**
+ * @class mw.ForeignUpload
+ * @extends mw.Upload
+ *
+ * Used to represent an upload in progress on the frontend.
+ *
+ * Subclassed to upload to a foreign API, with no other goodies. Use
+ * this for a generic foreign image repository on your wiki farm.
+ *
+ * Note you can provide the {@link #target target} or not - if the first argument is
+ * an object, we assume you want the default, and treat it as apiconfig
+ * instead.
+ *
+ * @constructor
+ * @param {string} [target] Used to set up the target
+ * wiki. If not remote, this class behaves identically to mw.Upload (unless further subclassed)
+ * Use the same names as set in $wgForeignFileRepos for this. Also,
+ * make sure there is an entry in the $wgForeignUploadTargets array for this name.
+ * @param {Object} [apiconfig] Passed to the constructor of mw.ForeignApi or mw.Api, as needed.
+ */
+ function ForeignUpload( target, apiconfig ) {
+ var api,
+ validTargets = mw.config.get( 'wgForeignUploadTargets' ),
+ upload = this;
+
+ if ( typeof target === 'object' ) {
+ // target probably wasn't passed in, it must
+ // be apiconfig
+ apiconfig = target;
+ target = undefined;
+ }
+
+ // * Use the given `target` first;
+ // * If not given, fall back to default (first) ForeignUploadTarget;
+ // * If none is configured, fall back to local uploads.
+ this.target = target || validTargets[ 0 ] || 'local';
+
+ // Now we have several different options.
+ // If the local wiki is the target, then we can skip a bunch of steps
+ // and just return an mw.Api object, because we don't need any special
+ // configuration for that.
+ // However, if the target is a remote wiki, we must check the API
+ // to confirm that the target is one that this site is configured to
+ // support.
+ if ( this.target === 'local' ) {
+ // If local uploads were requested, but they are disabled, fail.
+ if ( !mw.config.get( 'wgEnableUploads' ) ) {
+ throw new Error( 'Local uploads are disabled' );
+ }
+ // We'll ignore the CORS and centralauth stuff if the target is
+ // the local wiki.
+ this.apiPromise = $.Deferred().resolve( new mw.Api( apiconfig ) );
+ } else {
+ api = new mw.Api();
+ this.apiPromise = api.get( {
+ action: 'query',
+ meta: 'filerepoinfo',
+ friprop: [ 'name', 'scriptDirUrl', 'canUpload' ]
+ } ).then( function ( data ) {
+ var i, repo,
+ repos = data.query.repos;
+
+ // First pass - try to find the passed-in target and check
+ // that it's configured for uploads.
+ for ( i in repos ) {
+ repo = repos[ i ];
+
+ // Skip repos that are not our target, or if they
+ // are the target, cannot be uploaded to.
+ if ( repo.name === upload.target && repo.canUpload === '' ) {
+ return new mw.ForeignApi(
+ repo.scriptDirUrl + '/api.php',
+ apiconfig
+ );
+ }
+ }
+
+ throw new Error( 'Can not upload to requested foreign repo' );
+ } );
+ }
+
+ // Build the upload object without an API - this class overrides the
+ // actual API call methods to wait for the apiPromise to resolve
+ // before continuing.
+ mw.Upload.call( this, null );
+
+ if ( this.target !== 'local' ) {
+ // Keep these untranslated. We don't know the content language of the foreign wiki, best to
+ // stick to English in the text.
+ this.setComment( 'Cross-wiki upload from ' + location.host );
+ }
+ }
+
+ OO.inheritClass( ForeignUpload, mw.Upload );
+
+ /**
+ * @property {string} target
+ * Used to specify the target repository of the upload.
+ *
+ * If you set this to something that isn't 'local', you must be sure to
+ * add that target to $wgForeignUploadTargets in LocalSettings, and the
+ * repository must be set up to use CORS and CentralAuth.
+ *
+ * Most wikis use "shared" to refer to Wikimedia Commons, we assume that
+ * in this class and in the messages linked to it.
+ *
+ * Defaults to the first available foreign upload target,
+ * or to local uploads if no foreign target is configured.
+ */
+
+ /**
+ * Override from mw.Upload to make sure the API info is found and allowed
+ */
+ ForeignUpload.prototype.upload = function () {
+ var upload = this;
+ return this.apiPromise.then( function ( api ) {
+ upload.api = api;
+ return mw.Upload.prototype.upload.call( upload );
+ } );
+ };
+
+ /**
+ * Override from mw.Upload to make sure the API info is found and allowed
+ */
+ ForeignUpload.prototype.uploadToStash = function () {
+ var upload = this;
+ return this.apiPromise.then( function ( api ) {
+ upload.api = api;
+ return mw.Upload.prototype.uploadToStash.call( upload );
+ } );
+ };
+
+ mw.ForeignUpload = ForeignUpload;
+}( mediaWiki, OO, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.RegExp.js b/resources/src/mediawiki/mediawiki.RegExp.js
new file mode 100644
index 00000000..1da4ab4c
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.RegExp.js
@@ -0,0 +1,22 @@
+( function ( mw ) {
+ /**
+ * @class mw.RegExp
+ */
+ mw.RegExp = {
+ /**
+ * Escape string for safe inclusion in regular expression
+ *
+ * The following characters are escaped:
+ *
+ * \ { } ( ) | . ? * + - ^ $ [ ]
+ *
+ * @since 1.26
+ * @static
+ * @param {string} str String to escape
+ * @return {string} Escaped string
+ */
+ escape: function ( str ) {
+ return str.replace( /([\\{}()|.?*+\-\^$\[\]])/g, '\\$1' );
+ }
+ };
+}( mediaWiki ) );
diff --git a/resources/src/mediawiki/mediawiki.Title.js b/resources/src/mediawiki/mediawiki.Title.js
index 3efb7eca..910a78f8 100644
--- a/resources/src/mediawiki/mediawiki.Title.js
+++ b/resources/src/mediawiki/mediawiki.Title.js
@@ -4,6 +4,7 @@
* @since 1.18
*/
( function ( mw, $ ) {
+ /*jshint latedef:false */
/**
* @class mw.Title
@@ -108,7 +109,7 @@
return false;
}
ns = ns.toLowerCase();
- id = mw.config.get( 'wgNamespaceIds' )[ns];
+ id = mw.config.get( 'wgNamespaceIds' )[ ns ];
if ( id === undefined ) {
return false;
}
@@ -234,7 +235,7 @@
.replace( rUnderscoreTrim, '' );
// Process initial colon
- if ( title !== '' && title.charAt( 0 ) === ':' ) {
+ if ( title !== '' && title[ 0 ] === ':' ) {
// Initial colon means main namespace instead of specified default
namespace = NS_MAIN;
title = title
@@ -251,16 +252,16 @@
// Process namespace prefix (if any)
m = title.match( rSplit );
if ( m ) {
- id = getNsIdByName( m[1] );
+ id = getNsIdByName( m[ 1 ] );
if ( id !== false ) {
// Ordinary namespace
namespace = id;
- title = m[2];
+ title = m[ 2 ];
// For Talk:X pages, make sure X has no "namespace" prefix
if ( namespace === NS_TALK && ( m = title.match( rSplit ) ) ) {
// Disallow titles like Talk:File:x (subject should roundtrip: talk:file:x -> file:x -> file_talk:x)
- if ( getNsIdByName( m[1] ) !== false ) {
+ if ( getNsIdByName( m[ 1 ] ) !== false ) {
return false;
}
}
@@ -325,7 +326,7 @@
}
// Any remaining initial :s are illegal.
- if ( title.charAt( 0 ) === ':' ) {
+ if ( title[ 0 ] === ':' ) {
return false;
}
@@ -380,9 +381,9 @@
rules = sanitationRules;
for ( i = 0, ruleLength = rules.length; i < ruleLength; ++i ) {
- rule = rules[i];
+ rule = rules[ i ];
for ( m = 0, filterLength = filter.length; m < filterLength; ++m ) {
- if ( rule[filter[m]] ) {
+ if ( rule[ filter[ m ] ] ) {
s = s.replace( rule.pattern, rule.replace );
}
}
@@ -480,11 +481,6 @@
* @param {number} [defaultNamespace=NS_MAIN]
* If given, will used as default namespace for the given title.
* @param {Object} [options] additional options
- * @param {string} [options.fileExtension='']
- * If the title is about to be created for the Media or File namespace,
- * ensures the resulting Title has the correct extension. Useful, for example
- * on systems that predict the type by content-sniffing, not by file extension.
- * If different from empty string, `forUploading` is assumed.
* @param {boolean} [options.forUploading=true]
* Makes sure that a file is uploadable under the title returned.
* There are pages in the file namespace under which file upload is impossible.
@@ -492,7 +488,7 @@
* @return {mw.Title|null} A valid Title object or null if the input cannot be turned into a valid title
*/
Title.newFromUserInput = function ( title, defaultNamespace, options ) {
- var namespace, m, id, ext, parts, normalizeExtension;
+ var namespace, m, id, ext, parts;
// defaultNamespace is optional; check whether options moves up
if ( arguments.length < 3 && $.type( defaultNamespace ) === 'object' ) {
@@ -502,23 +498,16 @@
// merge options into defaults
options = $.extend( {
- fileExtension: '',
forUploading: true
}, options );
- normalizeExtension = function ( extension ) {
- // Remove only trailing space (that is removed by MW anyway)
- extension = extension.toLowerCase().replace( /\s*$/, '' );
- return extension;
- };
-
namespace = defaultNamespace === undefined ? NS_MAIN : defaultNamespace;
// Normalise whitespace and remove duplicates
title = $.trim( title.replace( rWhitespace, ' ' ) );
// Process initial colon
- if ( title !== '' && title.charAt( 0 ) === ':' ) {
+ if ( title !== '' && title[ 0 ] === ':' ) {
// Initial colon means main namespace instead of specified default
namespace = NS_MAIN;
title = title
@@ -531,16 +520,16 @@
// Process namespace prefix (if any)
m = title.match( rSplit );
if ( m ) {
- id = getNsIdByName( m[1] );
+ id = getNsIdByName( m[ 1 ] );
if ( id !== false ) {
// Ordinary namespace
namespace = id;
- title = m[2];
+ title = m[ 2 ];
}
}
if ( namespace === NS_MEDIA
- || ( ( options.forUploading || options.fileExtension ) && ( namespace === NS_FILE ) )
+ || ( options.forUploading && ( namespace === NS_FILE ) )
) {
title = sanitize( title, [ 'generalRule', 'fileRule' ] );
@@ -555,18 +544,6 @@
// Get the last part, which is supposed to be the file extension
ext = parts.pop();
- // Does the supplied file name carry the desired file extension?
- if ( options.fileExtension
- && normalizeExtension( ext ) !== normalizeExtension( options.fileExtension )
- ) {
-
- // No, push back, whatever there was after the dot
- parts.push( ext );
-
- // And add the desired file extension later
- ext = options.fileExtension;
- }
-
// Remove whitespace of the name part (that W/O extension)
title = $.trim( parts.join( '.' ) );
@@ -578,16 +555,8 @@
// Missing file extension
title = $.trim( parts.join( '.' ) );
- if ( options.fileExtension ) {
-
- // Cut, if too long and append the desired file extension
- title = trimFileNameToByteLength( title, options.fileExtension );
-
- } else {
-
- // Name has no file extension and a fallback wasn't provided either
- return null;
- }
+ // Name has no file extension and a fallback wasn't provided either
+ return null;
}
} else {
@@ -614,13 +583,11 @@
* @static
* @param {string} uncleanName The unclean file name including file extension but
* without namespace
- * @param {string} [fileExtension] the desired file extension
* @return {mw.Title|null} A valid Title object or null if the title is invalid
*/
- Title.newFromFileName = function ( uncleanName, fileExtension ) {
+ Title.newFromFileName = function ( uncleanName ) {
return Title.newFromUserInput( 'File:' + uncleanName, {
- fileExtension: fileExtension,
forUploading: true
} );
};
@@ -655,7 +622,7 @@
recount = regexes.length;
- src = img.jquery ? img[0].src : img.src;
+ src = img.jquery ? img[ 0 ].src : img.src;
matches = src.match( thumbPhpRegex );
@@ -666,11 +633,11 @@
decodedSrc = decodeURIComponent( src );
for ( i = 0; i < recount; i++ ) {
- regex = regexes[i];
+ regex = regexes[ i ];
matches = decodedSrc.match( regex );
- if ( matches && matches[1] ) {
- return mw.Title.newFromText( 'File:' + matches[1] );
+ if ( matches && matches[ 1 ] ) {
+ return mw.Title.newFromText( 'File:' + matches[ 1 ] );
}
}
@@ -690,9 +657,9 @@
obj = Title.exist.pages;
if ( type === 'string' ) {
- match = obj[title];
+ match = obj[ title ];
} else if ( type === 'object' && title instanceof Title ) {
- match = obj[title.toString()];
+ match = obj[ title.toString() ];
} else {
throw new Error( 'mw.Title.exists: title must be a string or an instance of Title' );
}
@@ -729,19 +696,46 @@
pages: {},
set: function ( titles, state ) {
- titles = $.isArray( titles ) ? titles : [titles];
+ titles = $.isArray( titles ) ? titles : [ titles ];
state = state === undefined ? true : !!state;
var i,
pages = this.pages,
len = titles.length;
for ( i = 0; i < len; i++ ) {
- pages[ titles[i] ] = state;
+ pages[ titles[ i ] ] = state;
}
return true;
}
};
+ /**
+ * Normalize a file extension to the common form, making it lowercase and checking some synonyms,
+ * and ensure it's clean. Extensions with non-alphanumeric characters will be discarded.
+ * Keep in sync with File::normalizeExtension() in PHP.
+ *
+ * @param {string} extension File extension (without the leading dot)
+ * @return {string} File extension in canonical form
+ */
+ Title.normalizeExtension = function ( extension ) {
+ var
+ lower = extension.toLowerCase(),
+ squish = {
+ htm: 'html',
+ jpeg: 'jpg',
+ mpeg: 'mpg',
+ tiff: 'tif',
+ ogv: 'ogg'
+ };
+ if ( squish.hasOwnProperty( lower ) ) {
+ return squish[ lower ];
+ } else if ( /^[0-9a-z]+$/.test( lower ) ) {
+ return lower;
+ } else {
+ return '';
+ }
+ };
+
/* Public members */
Title.prototype = {
@@ -782,11 +776,13 @@
* @return {string}
*/
getName: function () {
- if ( $.inArray( this.namespace, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ) {
+ if (
+ $.inArray( this.namespace, mw.config.get( 'wgCaseSensitiveNamespaces' ) ) !== -1 ||
+ !this.title.length
+ ) {
return this.title;
- } else {
- return $.ucFirst( this.title );
}
+ return this.title[ 0 ].toUpperCase() + this.title.slice( 1 );
},
/**
diff --git a/resources/src/mediawiki/mediawiki.Upload.BookletLayout.js b/resources/src/mediawiki/mediawiki.Upload.BookletLayout.js
new file mode 100644
index 00000000..dd199cef
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.Upload.BookletLayout.js
@@ -0,0 +1,543 @@
+( function ( $, mw ) {
+
+ /**
+ * mw.Upload.BookletLayout encapsulates the process of uploading a file
+ * to MediaWiki using the {@link mw.Upload upload model}.
+ * The booklet emits events that can be used to get the stashed
+ * upload and the final file. It can be extended to accept
+ * additional fields from the user for specific scenarios like
+ * for Commons, or campaigns.
+ *
+ * ## Structure
+ *
+ * The {@link OO.ui.BookletLayout booklet layout} has three steps:
+ *
+ * - **Upload**: Has a {@link OO.ui.SelectFileWidget field} to get the file object.
+ *
+ * - **Information**: Has a {@link OO.ui.FormLayout form} to collect metadata. This can be
+ * extended.
+ *
+ * - **Insert**: Has details on how to use the file that was uploaded.
+ *
+ * Each step has a form associated with it defined in
+ * {@link #renderUploadForm renderUploadForm},
+ * {@link #renderInfoForm renderInfoForm}, and
+ * {@link #renderInsertForm renderInfoForm}. The
+ * {@link #getFile getFile},
+ * {@link #getFilename getFilename}, and
+ * {@link #getText getText} methods are used to get
+ * the information filled in these forms, required to call
+ * {@link mw.Upload mw.Upload}.
+ *
+ * ## Usage
+ *
+ * See the {@link mw.Upload.Dialog upload dialog}.
+ *
+ * The {@link #event-fileUploaded fileUploaded},
+ * and {@link #event-fileSaved fileSaved} events can
+ * be used to get details of the upload.
+ *
+ * ## Extending
+ *
+ * To extend using {@link mw.Upload mw.Upload}, override
+ * {@link #renderInfoForm renderInfoForm} to render
+ * the form required for the specific use-case. Update the
+ * {@link #getFilename getFilename}, and
+ * {@link #getText getText} methods to return data
+ * from your newly created form. If you added new fields you'll also have
+ * to update the {@link #clear} method.
+ *
+ * If you plan to use a different upload model, apart from what is mentioned
+ * above, you'll also have to override the
+ * {@link #createUpload createUpload} method to
+ * return the new model. The {@link #saveFile saveFile}, and
+ * the {@link #uploadFile uploadFile} methods need to be
+ * overriden to use the new model and data returned from the forms.
+ *
+ * @class
+ * @extends OO.ui.BookletLayout
+ *
+ * @constructor
+ * @param {Object} config Configuration options
+ * @cfg {jQuery} [$overlay] Overlay to use for widgets in the booklet
+ */
+ mw.Upload.BookletLayout = function ( config ) {
+ // Parent constructor
+ mw.Upload.BookletLayout.parent.call( this, config );
+
+ this.$overlay = config.$overlay;
+
+ this.renderUploadForm();
+ this.renderInfoForm();
+ this.renderInsertForm();
+
+ this.addPages( [
+ new OO.ui.PageLayout( 'upload', {
+ scrollable: true,
+ padded: true,
+ content: [ this.uploadForm ]
+ } ),
+ new OO.ui.PageLayout( 'info', {
+ scrollable: true,
+ padded: true,
+ content: [ this.infoForm ]
+ } ),
+ new OO.ui.PageLayout( 'insert', {
+ scrollable: true,
+ padded: true,
+ content: [ this.insertForm ]
+ } )
+ ] );
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.Upload.BookletLayout, OO.ui.BookletLayout );
+
+ /* Events */
+
+ /**
+ * The file has finished uploading
+ *
+ * @event fileUploaded
+ */
+
+ /**
+ * The file has been saved to the database
+ *
+ * @event fileSaved
+ * @param {Object} imageInfo See mw.Upload#getImageInfo
+ */
+
+ /**
+ * The upload form has changed
+ *
+ * @event uploadValid
+ * @param {boolean} isValid The form is valid
+ */
+
+ /**
+ * The info form has changed
+ *
+ * @event infoValid
+ * @param {boolean} isValid The form is valid
+ */
+
+ /* Properties */
+
+ /**
+ * @property {OO.ui.FormLayout} uploadForm
+ * The form rendered in the first step to get the file object.
+ * Rendered in {@link #renderUploadForm renderUploadForm}.
+ */
+
+ /**
+ * @property {OO.ui.FormLayout} infoForm
+ * The form rendered in the second step to get metadata.
+ * Rendered in {@link #renderInfoForm renderInfoForm}
+ */
+
+ /**
+ * @property {OO.ui.FormLayout} insertForm
+ * The form rendered in the third step to show usage
+ * Rendered in {@link #renderInsertForm renderInsertForm}
+ */
+
+ /* Methods */
+
+ /**
+ * Initialize for a new upload
+ */
+ mw.Upload.BookletLayout.prototype.initialize = function () {
+ this.clear();
+ this.upload = this.createUpload();
+ this.setPage( 'upload' );
+ };
+
+ /**
+ * Create a new upload model
+ *
+ * @protected
+ * @return {mw.Upload} Upload model
+ */
+ mw.Upload.BookletLayout.prototype.createUpload = function () {
+ return new mw.Upload();
+ };
+
+ /* Uploading */
+
+ /**
+ * Uploads the file that was added in the upload form. Uses
+ * {@link #getFile getFile} to get the HTML5
+ * file object.
+ *
+ * @protected
+ * @fires fileUploaded
+ * @return {jQuery.Promise}
+ */
+ mw.Upload.BookletLayout.prototype.uploadFile = function () {
+ var deferred = $.Deferred(),
+ layout = this,
+ file = this.getFile();
+
+ this.filenameWidget.setValue( file.name );
+ this.setPage( 'info' );
+
+ this.upload.setFile( file );
+ // Explicitly set the filename so that the old filename isn't used in case of retry
+ this.upload.setFilenameFromFile();
+
+ this.uploadPromise = this.upload.uploadToStash();
+ this.uploadPromise.then( function () {
+ deferred.resolve();
+ layout.emit( 'fileUploaded' );
+ }, function () {
+ // These errors will be thrown while the user is on the info page.
+ // Pretty sure it's impossible to get a warning other than 'stashfailed' here, which should
+ // really be an error...
+ var errorMessage = layout.getErrorMessageForStateDetails();
+ deferred.reject( errorMessage );
+ } );
+
+ // If there is an error in uploading, come back to the upload page
+ deferred.fail( function () {
+ layout.setPage( 'upload' );
+ } );
+
+ return deferred;
+ };
+
+ /**
+ * Saves the stash finalizes upload. Uses
+ * {@link #getFilename getFilename}, and
+ * {@link #getText getText} to get details from
+ * the form.
+ *
+ * @protected
+ * @fires fileSaved
+ * @returns {jQuery.Promise} Rejects the promise with an
+ * {@link OO.ui.Error error}, or resolves if the upload was successful.
+ */
+ mw.Upload.BookletLayout.prototype.saveFile = function () {
+ var layout = this,
+ deferred = $.Deferred();
+
+ this.upload.setFilename( this.getFilename() );
+ this.upload.setText( this.getText() );
+
+ this.uploadPromise.then( function () {
+ layout.upload.finishStashUpload().then( function () {
+ var name;
+
+ // Normalize page name and localise the 'File:' prefix
+ name = new mw.Title( 'File:' + layout.upload.getFilename() ).toString();
+ layout.filenameUsageWidget.setValue( '[[' + name + ']]' );
+ layout.setPage( 'insert' );
+
+ deferred.resolve();
+ layout.emit( 'fileSaved', layout.upload.getImageInfo() );
+ }, function () {
+ var errorMessage = layout.getErrorMessageForStateDetails();
+ deferred.reject( errorMessage );
+ } );
+ } );
+
+ return deferred.promise();
+ };
+
+ /**
+ * Get an error message (as OO.ui.Error object) that should be displayed to the user for current
+ * state and state details.
+ *
+ * @protected
+ * @returns {OO.ui.Error} Error to display for given state and details.
+ */
+ mw.Upload.BookletLayout.prototype.getErrorMessageForStateDetails = function () {
+ var message,
+ state = this.upload.getState(),
+ stateDetails = this.upload.getStateDetails(),
+ error = stateDetails.error,
+ warnings = stateDetails.upload && stateDetails.upload.warnings;
+
+ if ( state === mw.Upload.State.ERROR ) {
+ // HACK We should either have a hook here to allow TitleBlacklist to handle this, or just have
+ // TitleBlacklist produce sane error messages that can be displayed without arcane knowledge
+ if ( error.info === 'TitleBlacklist prevents this title from being created' ) {
+ // HACK Apparently the only reliable way to determine whether TitleBlacklist was involved
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ // HACK TitleBlacklist doesn't have a sensible message, this one is from UploadWizard
+ mw.message( 'api-error-blacklisted' ).parse()
+ ),
+ { recoverable: false }
+ );
+ }
+
+ message = mw.message( 'api-error-' + error.code );
+ if ( !message.exists() ) {
+ message = mw.message( 'api-error-unknownerror', JSON.stringify( stateDetails ) );
+ }
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ message.parse()
+ ),
+ { recoverable: false }
+ );
+ }
+
+ if ( state === mw.Upload.State.WARNING ) {
+ // We could get more than one of these errors, these are in order
+ // of importance. For example fixing the thumbnail like file name
+ // won't help the fact that the file already exists.
+ if ( warnings.stashfailed !== undefined ) {
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ mw.message( 'api-error-stashfailed' ).parse()
+ ),
+ { recoverable: false }
+ );
+ } else if ( warnings.exists !== undefined ) {
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ mw.message( 'fileexists', 'File:' + warnings.exists ).parse()
+ ),
+ { recoverable: false }
+ );
+ } else if ( warnings[ 'page-exists' ] !== undefined ) {
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ mw.message( 'filepageexists', 'File:' + warnings[ 'page-exists' ] ).parse()
+ ),
+ { recoverable: false }
+ );
+ } else if ( warnings.duplicate !== undefined ) {
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ mw.message( 'api-error-duplicate', warnings.duplicate.length ).parse()
+ ),
+ { recoverable: false }
+ );
+ } else if ( warnings[ 'thumb-name' ] !== undefined ) {
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ mw.message( 'filename-thumb-name' ).parse()
+ ),
+ { recoverable: false }
+ );
+ } else if ( warnings[ 'bad-prefix' ] !== undefined ) {
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ mw.message( 'filename-bad-prefix', warnings[ 'bad-prefix' ] ).parse()
+ ),
+ { recoverable: false }
+ );
+ } else if ( warnings[ 'duplicate-archive' ] !== undefined ) {
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ mw.message( 'api-error-duplicate-archive', 1 ).parse()
+ ),
+ { recoverable: false }
+ );
+ } else if ( warnings.badfilename !== undefined ) {
+ // Change the name if the current name isn't acceptable
+ // TODO This might not really be the best place to do this
+ this.filenameWidget.setValue( warnings.badfilename );
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ mw.message( 'badfilename', warnings.badfilename ).parse()
+ )
+ );
+ } else {
+ return new OO.ui.Error(
+ $( '<p>' ).html(
+ // Let's get all the help we can if we can't pin point the error
+ mw.message( 'api-error-unknown-warning', JSON.stringify( stateDetails ) ).parse()
+ ),
+ { recoverable: false }
+ );
+ }
+ }
+ };
+
+ /* Form renderers */
+
+ /**
+ * Renders and returns the upload form and sets the
+ * {@link #uploadForm uploadForm} property.
+ *
+ * @protected
+ * @fires selectFile
+ * @returns {OO.ui.FormLayout}
+ */
+ mw.Upload.BookletLayout.prototype.renderUploadForm = function () {
+ var fieldset;
+
+ this.selectFileWidget = new OO.ui.SelectFileWidget();
+ fieldset = new OO.ui.FieldsetLayout( { label: mw.msg( 'upload-form-label-select-file' ) } );
+ fieldset.addItems( [ this.selectFileWidget ] );
+ this.uploadForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
+
+ // Validation
+ this.selectFileWidget.on( 'change', this.onUploadFormChange.bind( this ) );
+
+ return this.uploadForm;
+ };
+
+ /**
+ * Handle change events to the upload form
+ *
+ * @protected
+ * @fires uploadValid
+ */
+ mw.Upload.BookletLayout.prototype.onUploadFormChange = function () {
+ this.emit( 'uploadValid', !!this.selectFileWidget.getValue() );
+ };
+
+ /**
+ * Renders and returns the information form for collecting
+ * metadata and sets the {@link #infoForm infoForm}
+ * property.
+ *
+ * @protected
+ * @returns {OO.ui.FormLayout}
+ */
+ mw.Upload.BookletLayout.prototype.renderInfoForm = function () {
+ var fieldset;
+
+ this.filenameWidget = new OO.ui.TextInputWidget( {
+ indicator: 'required',
+ required: true,
+ validate: /.+/
+ } );
+ this.descriptionWidget = new OO.ui.TextInputWidget( {
+ indicator: 'required',
+ required: true,
+ validate: /.+/,
+ multiline: true,
+ autosize: true
+ } );
+
+ fieldset = new OO.ui.FieldsetLayout( {
+ label: mw.msg( 'upload-form-label-infoform-title' )
+ } );
+ fieldset.addItems( [
+ new OO.ui.FieldLayout( this.filenameWidget, {
+ label: mw.msg( 'upload-form-label-infoform-name' ),
+ align: 'top'
+ } ),
+ new OO.ui.FieldLayout( this.descriptionWidget, {
+ label: mw.msg( 'upload-form-label-infoform-description' ),
+ align: 'top'
+ } )
+ ] );
+ this.infoForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
+
+ this.filenameWidget.on( 'change', this.onInfoFormChange.bind( this ) );
+ this.descriptionWidget.on( 'change', this.onInfoFormChange.bind( this ) );
+
+ return this.infoForm;
+ };
+
+ /**
+ * Handle change events to the info form
+ *
+ * @protected
+ * @fires infoValid
+ */
+ mw.Upload.BookletLayout.prototype.onInfoFormChange = function () {
+ var layout = this;
+ $.when(
+ this.filenameWidget.getValidity(),
+ this.descriptionWidget.getValidity()
+ ).done( function () {
+ layout.emit( 'infoValid', true );
+ } ).fail( function () {
+ layout.emit( 'infoValid', false );
+ } );
+ };
+
+ /**
+ * Renders and returns the insert form to show file usage and
+ * sets the {@link #insertForm insertForm} property.
+ *
+ * @protected
+ * @returns {OO.ui.FormLayout}
+ */
+ mw.Upload.BookletLayout.prototype.renderInsertForm = function () {
+ var fieldset;
+
+ this.filenameUsageWidget = new OO.ui.TextInputWidget();
+ fieldset = new OO.ui.FieldsetLayout( {
+ label: mw.msg( 'upload-form-label-usage-title' )
+ } );
+ fieldset.addItems( [
+ new OO.ui.FieldLayout( this.filenameUsageWidget, {
+ label: mw.msg( 'upload-form-label-usage-filename' ),
+ align: 'top'
+ } )
+ ] );
+ this.insertForm = new OO.ui.FormLayout( { items: [ fieldset ] } );
+
+ return this.insertForm;
+ };
+
+ /* Getters */
+
+ /**
+ * Gets the file object from the
+ * {@link #uploadForm upload form}.
+ *
+ * @protected
+ * @returns {File|null}
+ */
+ mw.Upload.BookletLayout.prototype.getFile = function () {
+ return this.selectFileWidget.getValue();
+ };
+
+ /**
+ * Gets the file name from the
+ * {@link #infoForm information form}.
+ *
+ * @protected
+ * @returns {string}
+ */
+ mw.Upload.BookletLayout.prototype.getFilename = function () {
+ return this.filenameWidget.getValue();
+ };
+
+ /**
+ * Gets the page text from the
+ * {@link #infoForm information form}.
+ *
+ * @protected
+ * @returns {string}
+ */
+ mw.Upload.BookletLayout.prototype.getText = function () {
+ return this.descriptionWidget.getValue();
+ };
+
+ /* Setters */
+
+ /**
+ * Sets the file object
+ *
+ * @protected
+ * @param {File|null} file File to select
+ */
+ mw.Upload.BookletLayout.prototype.setFile = function ( file ) {
+ this.selectFileWidget.setValue( file );
+ };
+
+ /**
+ * Clear the values of all fields
+ *
+ * @protected
+ */
+ mw.Upload.BookletLayout.prototype.clear = function () {
+ this.selectFileWidget.setValue( null );
+ this.filenameWidget.setValue( null ).setValidityFlag( true );
+ this.descriptionWidget.setValue( null ).setValidityFlag( true );
+ this.filenameUsageWidget.setValue( null );
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki/mediawiki.Upload.Dialog.js b/resources/src/mediawiki/mediawiki.Upload.Dialog.js
new file mode 100644
index 00000000..03e39718
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.Upload.Dialog.js
@@ -0,0 +1,205 @@
+( function ( $, mw ) {
+
+ /**
+ * mw.Upload.Dialog controls a {@link mw.Upload.BookletLayout BookletLayout}.
+ *
+ * ## Usage
+ *
+ * To use, setup a {@link OO.ui.WindowManager window manager} like for normal
+ * dialogs:
+ *
+ * var uploadDialog = new mw.Upload.Dialog();
+ * var windowManager = new OO.ui.WindowManager();
+ * $( 'body' ).append( windowManager.$element );
+ * windowManager.addWindows( [ uploadDialog ] );
+ * windowManager.openWindow( uploadDialog );
+ *
+ * The dialog's closing promise can be used to get details of the upload.
+ *
+ * @class mw.Upload.Dialog
+ * @uses mw.Upload
+ * @extends OO.ui.ProcessDialog
+ * @cfg {Function} [bookletClass=mw.Upload.BookletLayout] Booklet class to be
+ * used for the steps
+ * @cfg {Object} [booklet] Booklet constructor configuration
+ */
+ mw.Upload.Dialog = function ( config ) {
+ // Config initialization
+ config = $.extend( {
+ bookletClass: mw.Upload.BookletLayout
+ }, config );
+
+ // Parent constructor
+ mw.Upload.Dialog.parent.call( this, config );
+
+ // Initialize
+ this.bookletClass = config.bookletClass;
+ this.bookletConfig = config.booklet;
+ };
+
+ /* Setup */
+
+ OO.inheritClass( mw.Upload.Dialog, OO.ui.ProcessDialog );
+
+ /* Static Properties */
+
+ /**
+ * @inheritdoc
+ * @property title
+ */
+ /*jshint -W024*/
+ mw.Upload.Dialog.static.title = mw.msg( 'upload-dialog-title' );
+
+ /**
+ * @inheritdoc
+ * @property actions
+ */
+ mw.Upload.Dialog.static.actions = [
+ {
+ flags: 'safe',
+ action: 'cancel',
+ label: mw.msg( 'upload-dialog-button-cancel' ),
+ modes: [ 'upload', 'insert', 'info' ]
+ },
+ {
+ flags: [ 'primary', 'progressive' ],
+ label: mw.msg( 'upload-dialog-button-done' ),
+ action: 'insert',
+ modes: 'insert'
+ },
+ {
+ flags: [ 'primary', 'constructive' ],
+ label: mw.msg( 'upload-dialog-button-save' ),
+ action: 'save',
+ modes: 'info'
+ },
+ {
+ flags: [ 'primary', 'progressive' ],
+ label: mw.msg( 'upload-dialog-button-upload' ),
+ action: 'upload',
+ modes: 'upload'
+ }
+ ];
+
+ /*jshint +W024*/
+
+ /* Methods */
+
+ /**
+ * @inheritdoc
+ */
+ mw.Upload.Dialog.prototype.initialize = function () {
+ // Parent method
+ mw.Upload.Dialog.parent.prototype.initialize.call( this );
+
+ this.uploadBooklet = this.createUploadBooklet();
+ this.uploadBooklet.connect( this, {
+ set: 'onUploadBookletSet',
+ uploadValid: 'onUploadValid',
+ infoValid: 'onInfoValid'
+ } );
+
+ this.$body.append( this.uploadBooklet.$element );
+ };
+
+ /**
+ * Create an upload booklet
+ *
+ * @protected
+ * @return {mw.Upload.BookletLayout} An upload booklet
+ */
+ mw.Upload.Dialog.prototype.createUploadBooklet = function () {
+ return new this.bookletClass( $.extend( {
+ $overlay: this.$overlay
+ }, this.bookletConfig ) );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.Upload.Dialog.prototype.getBodyHeight = function () {
+ return 300;
+ };
+
+ /**
+ * Handle panelNameSet events from the upload booklet
+ *
+ * @protected
+ * @param {OO.ui.PageLayout} page Current page
+ */
+ mw.Upload.Dialog.prototype.onUploadBookletSet = function ( page ) {
+ this.actions.setMode( page.getName() );
+ this.actions.setAbilities( { upload: false, save: false } );
+ };
+
+ /**
+ * Handle uploadValid events
+ *
+ * {@link OO.ui.ActionSet#setAbilities Sets abilities}
+ * for the dialog accordingly.
+ *
+ * @protected
+ * @param {boolean} isValid The panel is complete and valid
+ */
+ mw.Upload.Dialog.prototype.onUploadValid = function ( isValid ) {
+ this.actions.setAbilities( { upload: isValid } );
+ };
+
+ /**
+ * Handle infoValid events
+ *
+ * {@link OO.ui.ActionSet#setAbilities Sets abilities}
+ * for the dialog accordingly.
+ *
+ * @protected
+ * @param {boolean} isValid The panel is complete and valid
+ */
+ mw.Upload.Dialog.prototype.onInfoValid = function ( isValid ) {
+ this.actions.setAbilities( { save: isValid } );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.Upload.Dialog.prototype.getSetupProcess = function ( data ) {
+ return mw.Upload.Dialog.parent.prototype.getSetupProcess.call( this, data )
+ .next( function () {
+ this.uploadBooklet.initialize();
+ }, this );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.Upload.Dialog.prototype.getActionProcess = function ( action ) {
+ var dialog = this;
+
+ if ( action === 'upload' ) {
+ return new OO.ui.Process( this.uploadBooklet.uploadFile() );
+ }
+ if ( action === 'save' ) {
+ return new OO.ui.Process( this.uploadBooklet.saveFile() );
+ }
+ if ( action === 'insert' ) {
+ return new OO.ui.Process( function () {
+ dialog.close( dialog.upload );
+ } );
+ }
+ if ( action === 'cancel' ) {
+ return new OO.ui.Process( this.close() );
+ }
+
+ return mw.Upload.Dialog.parent.prototype.getActionProcess.call( this, action );
+ };
+
+ /**
+ * @inheritdoc
+ */
+ mw.Upload.Dialog.prototype.getTeardownProcess = function ( data ) {
+ return mw.Upload.Dialog.parent.prototype.getTeardownProcess.call( this, data )
+ .next( function () {
+ this.uploadBooklet.clear();
+ }, this );
+ };
+
+}( jQuery, mediaWiki ) );
diff --git a/resources/src/mediawiki/mediawiki.Upload.js b/resources/src/mediawiki/mediawiki.Upload.js
new file mode 100644
index 00000000..4f8789de
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.Upload.js
@@ -0,0 +1,368 @@
+( function ( mw, $ ) {
+ var UP;
+
+ /**
+ * @class mw.Upload
+ *
+ * Used to represent an upload in progress on the frontend.
+ * Most of the functionality is implemented in mw.Api.plugin.upload,
+ * but this model class will tie it together as well as let you perform
+ * actions in a logical way.
+ *
+ * A simple example:
+ *
+ * var file = new OO.ui.SelectFileWidget(),
+ * button = new OO.ui.ButtonWidget( { label: 'Save' } ),
+ * upload = new mw.Upload;
+ *
+ * button.on( 'click', function () {
+ * upload.setFile( file.getValue() );
+ * upload.setFilename( file.getValue().name );
+ * upload.upload();
+ * } );
+ *
+ * $( 'body' ).append( file.$element, button.$element );
+ *
+ * You can also choose to {@link #uploadToStash stash the upload} and
+ * {@link #finishStashUpload finalize} it later:
+ *
+ * var file, // Some file object
+ * upload = new mw.Upload,
+ * stashPromise = $.Deferred();
+ *
+ * upload.setFile( file );
+ * upload.uploadToStash().then( function () {
+ * stashPromise.resolve();
+ * } );
+ *
+ * stashPromise.then( function () {
+ * upload.setFilename( 'foo' );
+ * upload.setText( 'bar' );
+ * upload.finishStashUpload().then( function () {
+ * console.log( 'Done!' );
+ * } );
+ * } );
+ *
+ * @constructor
+ * @param {Object|mw.Api} [apiconfig] A mw.Api object (or subclass), or configuration
+ * to pass to the constructor of mw.Api.
+ */
+ function Upload( apiconfig ) {
+ this.api = ( apiconfig instanceof mw.Api ) ? apiconfig : new mw.Api( apiconfig );
+
+ this.watchlist = false;
+ this.text = '';
+ this.comment = '';
+ this.filename = null;
+ this.file = null;
+ this.setState( Upload.State.NEW );
+
+ this.imageinfo = undefined;
+ }
+
+ UP = Upload.prototype;
+
+ /**
+ * Set the text of the file page, to be created on file upload.
+ *
+ * @param {string} text
+ */
+ UP.setText = function ( text ) {
+ this.text = text;
+ };
+
+ /**
+ * Set the filename, to be finalized on upload.
+ *
+ * @param {string} filename
+ */
+ UP.setFilename = function ( filename ) {
+ this.filename = filename;
+ };
+
+ /**
+ * Sets the filename based on the filename as it was on the upload.
+ */
+ UP.setFilenameFromFile = function () {
+ var file = this.getFile();
+ if ( !file ) {
+ return;
+ }
+ if ( file.nodeType && file.nodeType === Node.ELEMENT_NODE ) {
+ // File input element, use getBasename to cut out the path
+ this.setFilename( this.getBasename( file.value ) );
+ } else if ( file.name ) {
+ // HTML5 FileAPI File object, but use getBasename to be safe
+ this.setFilename( this.getBasename( file.name ) );
+ } else {
+ // If we ever implement uploading files from clipboard, they might not have a name
+ this.setFilename( '?' );
+ }
+ };
+
+ /**
+ * Set the file to be uploaded.
+ *
+ * @param {HTMLInputElement|File} file
+ */
+ UP.setFile = function ( file ) {
+ this.file = file;
+ };
+
+ /**
+ * Set whether the file should be watchlisted after upload.
+ *
+ * @param {boolean} watchlist
+ */
+ UP.setWatchlist = function ( watchlist ) {
+ this.watchlist = watchlist;
+ };
+
+ /**
+ * Set the edit comment for the upload.
+ *
+ * @param {string} comment
+ */
+ UP.setComment = function ( comment ) {
+ this.comment = comment;
+ };
+
+ /**
+ * Get the text of the file page, to be created on file upload.
+ *
+ * @return {string}
+ */
+ UP.getText = function () {
+ return this.text;
+ };
+
+ /**
+ * Get the filename, to be finalized on upload.
+ *
+ * @return {string}
+ */
+ UP.getFilename = function () {
+ return this.filename;
+ };
+
+ /**
+ * Get the file being uploaded.
+ *
+ * @return {HTMLInputElement|File}
+ */
+ UP.getFile = function () {
+ return this.file;
+ };
+
+ /**
+ * Get the boolean for whether the file will be watchlisted after upload.
+ *
+ * @return {boolean}
+ */
+ UP.getWatchlist = function () {
+ return this.watchlist;
+ };
+
+ /**
+ * Get the current value of the edit comment for the upload.
+ *
+ * @return {string}
+ */
+ UP.getComment = function () {
+ return this.comment;
+ };
+
+ /**
+ * Gets the base filename from a path name.
+ *
+ * @param {string} path
+ * @return {string}
+ */
+ UP.getBasename = function ( path ) {
+ if ( path === undefined || path === null ) {
+ return '';
+ }
+
+ // Find the index of the last path separator in the
+ // path, and add 1. Then, take the entire string after that.
+ return path.slice(
+ Math.max(
+ path.lastIndexOf( '/' ),
+ path.lastIndexOf( '\\' )
+ ) + 1
+ );
+ };
+
+ /**
+ * Sets the state and state details (if any) of the upload.
+ *
+ * @param {mw.Upload.State} state
+ * @param {Object} stateDetails
+ */
+ UP.setState = function ( state, stateDetails ) {
+ this.state = state;
+ this.stateDetails = stateDetails;
+ };
+
+ /**
+ * Gets the state of the upload.
+ *
+ * @return {mw.Upload.State}
+ */
+ UP.getState = function () {
+ return this.state;
+ };
+
+ /**
+ * Gets details of the current state.
+ *
+ * @return {string}
+ */
+ UP.getStateDetails = function () {
+ return this.stateDetails;
+ };
+
+ /**
+ * Get the imageinfo object for the finished upload.
+ * Only available once the upload is finished! Don't try to get it
+ * beforehand.
+ *
+ * @return {Object|undefined}
+ */
+ UP.getImageInfo = function () {
+ return this.imageinfo;
+ };
+
+ /**
+ * Upload the file directly.
+ *
+ * @return {jQuery.Promise}
+ */
+ UP.upload = function () {
+ var upload = this;
+
+ if ( !this.getFile() ) {
+ return $.Deferred().reject( 'No file to upload. Call setFile to add one.' );
+ }
+
+ if ( !this.getFilename() ) {
+ return $.Deferred().reject( 'No filename set. Call setFilename to add one.' );
+ }
+
+ this.setState( Upload.State.UPLOADING );
+
+ return this.api.upload( this.getFile(), {
+ watchlist: ( this.getWatchlist() ) ? 1 : undefined,
+ comment: this.getComment(),
+ filename: this.getFilename(),
+ text: this.getText()
+ } ).then( function ( result ) {
+ upload.setState( Upload.State.UPLOADED );
+ upload.imageinfo = result.upload.imageinfo;
+ return result;
+ }, function ( errorCode, result ) {
+ if ( result && result.upload && result.upload.warnings ) {
+ upload.setState( Upload.State.WARNING, result );
+ } else {
+ upload.setState( Upload.State.ERROR, result );
+ }
+ return $.Deferred().reject( errorCode, result );
+ } );
+ };
+
+ /**
+ * Upload the file to the stash to be completed later.
+ *
+ * @return {jQuery.Promise}
+ */
+ UP.uploadToStash = function () {
+ var upload = this;
+
+ if ( !this.getFile() ) {
+ return $.Deferred().reject( 'No file to upload. Call setFile to add one.' );
+ }
+
+ if ( !this.getFilename() ) {
+ this.setFilenameFromFile();
+ }
+
+ this.setState( Upload.State.UPLOADING );
+
+ this.stashPromise = this.api.uploadToStash( this.getFile(), {
+ filename: this.getFilename()
+ } ).then( function ( finishStash ) {
+ upload.setState( Upload.State.STASHED );
+ return finishStash;
+ }, function ( errorCode, result ) {
+ if ( result && result.upload && result.upload.warnings ) {
+ upload.setState( Upload.State.WARNING, result );
+ } else {
+ upload.setState( Upload.State.ERROR, result );
+ }
+ return $.Deferred().reject( errorCode, result );
+ } );
+
+ return this.stashPromise;
+ };
+
+ /**
+ * Finish a stash upload.
+ *
+ * @return {jQuery.Promise}
+ */
+ UP.finishStashUpload = function () {
+ var upload = this;
+
+ if ( !this.stashPromise ) {
+ return $.Deferred().reject( 'This upload has not been stashed, please upload it to the stash first.' );
+ }
+
+ return this.stashPromise.then( function ( finishStash ) {
+ upload.setState( Upload.State.UPLOADING );
+
+ return finishStash( {
+ watchlist: ( upload.getWatchlist() ) ? 1 : undefined,
+ comment: upload.getComment(),
+ filename: upload.getFilename(),
+ text: upload.getText()
+ } ).then( function ( result ) {
+ upload.setState( Upload.State.UPLOADED );
+ upload.imageinfo = result.upload.imageinfo;
+ return result;
+ }, function ( errorCode, result ) {
+ if ( result && result.upload && result.upload.warnings ) {
+ upload.setState( Upload.State.WARNING, result );
+ } else {
+ upload.setState( Upload.State.ERROR, result );
+ }
+ return $.Deferred().reject( errorCode, result );
+ } );
+ } );
+ };
+
+ /**
+ * @enum mw.Upload.State
+ * State of uploads represented in simple terms.
+ */
+ Upload.State = {
+ /** Upload not yet started */
+ NEW: 0,
+
+ /** Upload finished, but there was a warning */
+ WARNING: 1,
+
+ /** Upload finished, but there was an error */
+ ERROR: 2,
+
+ /** Upload in progress */
+ UPLOADING: 3,
+
+ /** Upload finished, but not published, call #finishStashUpload */
+ STASHED: 4,
+
+ /** Upload finished and published */
+ UPLOADED: 5
+ };
+
+ mw.Upload = Upload;
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.Uri.js b/resources/src/mediawiki/mediawiki.Uri.js
index abfb2790..29b224ee 100644
--- a/resources/src/mediawiki/mediawiki.Uri.js
+++ b/resources/src/mediawiki/mediawiki.Uri.js
@@ -68,19 +68,25 @@
if ( val === undefined || val === null || val === '' ) {
return '';
}
+ /* jshint latedef:false */
return pre + ( raw ? val : mw.Uri.encode( val ) ) + post;
+ /* jshint latedef:true */
}
/**
* Regular expressions to parse many common URIs.
*
+ * As they are gnarly, they have been moved to separate files to allow us to format them in the
+ * 'extended' regular expression format (which JavaScript normally doesn't support). The subset of
+ * features handled is minimal, but just the free whitespace gives us a lot.
+ *
* @private
* @static
* @property {Object} parser
*/
var parser = {
- strict: /^(?:([^:\/?#]+):)?(?:\/\/(?:(?:([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?([^:\/?#]*)(?::(\d*))?)?((?:[^?#\/]*\/)*[^?#]*)(?:\?([^#]*))?(?:#(.*))?/,
- loose: /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?(?:(?:([^:@\/?#]*)(?::([^:@\/?#]*))?)?@)?([^:\/?#]*)(?::(\d*))?((?:\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?[^?#\/]*)(?:\?([^#]*))?(?:#(.*))?/
+ strict: mw.template.get( 'mediawiki.Uri', 'strict.regexp' ).render(),
+ loose: mw.template.get( 'mediawiki.Uri', 'loose.regexp' ).render()
},
/**
@@ -169,6 +175,7 @@
* @param {boolean} [options.overrideKeys=false] Whether to let duplicate query parameters
* override each other (`true`) or automagically convert them to an array (`false`).
*/
+ /* jshint latedef:false */
function Uri( uri, options ) {
var prop,
defaultUri = getDefaultUri();
@@ -188,10 +195,10 @@
// Only copy direct properties, not inherited ones
if ( uri.hasOwnProperty( prop ) ) {
// Deep copy object properties
- if ( $.isArray( uri[prop] ) || $.isPlainObject( uri[prop] ) ) {
- this[prop] = $.extend( true, {}, uri[prop] );
+ if ( $.isArray( uri[ prop ] ) || $.isPlainObject( uri[ prop ] ) ) {
+ this[ prop ] = $.extend( true, {}, uri[ prop ] );
} else {
- this[prop] = uri[prop];
+ this[ prop ] = uri[ prop ];
}
}
}
@@ -216,7 +223,7 @@
this.port = defaultUri.port;
}
}
- if ( this.path && this.path.charAt( 0 ) !== '/' ) {
+ if ( this.path && this.path[ 0 ] !== '/' ) {
// A real relative URL, relative to defaultUri.path. We can't really handle that since we cannot
// figure out whether the last path component of defaultUri.path is a directory or a file.
throw new Error( 'Bad constructor arguments' );
diff --git a/resources/src/mediawiki/mediawiki.Uri.loose.regexp b/resources/src/mediawiki/mediawiki.Uri.loose.regexp
new file mode 100644
index 00000000..300ab3ba
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.Uri.loose.regexp
@@ -0,0 +1,22 @@
+^
+(?:
+ (?![^:@]+:[^:@/]*@)
+ (?<protocol>[^:/?#.]+):
+)?
+(?://)?
+(?:(?:
+ (?<user>[^:@/?#]*)
+ (?::(?<password>[^:@/?#]*))?
+)?@)?
+(?<host>[^:/?#]*)
+(?::(?<port>\d*))?
+(
+ (?:/
+ (?:[^?#]
+ (?![^?#/]*\.[^?#/.]+(?:[?#]|$))
+ )*/?
+ )?
+ [^?#/]*
+)
+(?:\?(?<query>[^#]*))?
+(?:\#(?<fragment>.*))?
diff --git a/resources/src/mediawiki/mediawiki.Uri.strict.regexp b/resources/src/mediawiki/mediawiki.Uri.strict.regexp
new file mode 100644
index 00000000..2ac7d2fc
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.Uri.strict.regexp
@@ -0,0 +1,13 @@
+^
+(?:(?<protocol>[^:/?#]+):)?
+(?://(?:
+ (?:
+ (?<user>[^:@/?#]*)
+ (?::(?<password>[^:@/?#]*))?
+ )?@)?
+ (?<host>[^:/?#]*)
+ (?::(?<port>\d*))?
+)?
+(?<path>(?:[^?#/]*/)*[^?#]*)
+(?:\?(?<query>[^#]*))?
+(?:\#(?<fragment>.*))?
diff --git a/resources/src/mediawiki/mediawiki.apihelp.css b/resources/src/mediawiki/mediawiki.apihelp.css
index d1272323..7d7b413a 100644
--- a/resources/src/mediawiki/mediawiki.apihelp.css
+++ b/resources/src/mediawiki/mediawiki.apihelp.css
@@ -29,6 +29,10 @@ div.apihelp-linktrail {
color: red;
}
+.apihelp-unknown {
+ color: #888;
+}
+
.apihelp-empty {
color: #888;
}
diff --git a/resources/src/mediawiki/mediawiki.confirmCloseWindow.js b/resources/src/mediawiki/mediawiki.confirmCloseWindow.js
index 7fc5c424..4d0c1352 100644
--- a/resources/src/mediawiki/mediawiki.confirmCloseWindow.js
+++ b/resources/src/mediawiki/mediawiki.confirmCloseWindow.js
@@ -1,3 +1,4 @@
+/* jshint devel: true */
( function ( mw, $ ) {
/**
* @method confirmCloseWindow
@@ -7,11 +8,22 @@
* 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.
+ * restored when you execute the returned release() function.
*
* var allowCloseWindow = mw.confirmCloseWindow();
* // ... do stuff that can't be interrupted ...
- * allowCloseWindow();
+ * allowCloseWindow.release();
+ *
+ * The second function returned is a trigger function to trigger the check and an alert
+ * window manually, e.g.:
+ *
+ * var allowCloseWindow = mw.confirmCloseWindow();
+ * // ... do stuff that can't be interrupted ...
+ * if ( allowCloseWindow.trigger() ) {
+ * // don't do anything (e.g. destroy the input field)
+ * } else {
+ * // do whatever you wanted to do
+ * }
*
* @param {Object} [options]
* @param {string} [options.namespace] Namespace for the event registration
@@ -19,12 +31,13 @@
* @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
+ * @return {Object} An object of functions to work with this module
*/
mw.confirmCloseWindow = function ( options ) {
var savedUnloadHandler,
mainEventName = 'beforeunload',
- showEventName = 'pageshow';
+ showEventName = 'pageshow',
+ message;
options = $.extend( {
message: mw.message( 'mwe-prevent-close' ).text(),
@@ -36,6 +49,12 @@
showEventName += '.' + options.namespace;
}
+ if ( $.isFunction( options.message ) ) {
+ message = options.message();
+ } else {
+ message = options.message;
+ }
+
$( window ).on( mainEventName, function () {
if ( options.test() ) {
// remove the handler while the alert is showing - otherwise breaks caching in Firefox (3?).
@@ -47,11 +66,7 @@
}, 1 );
// show an alert with this message
- if ( $.isFunction( options.message ) ) {
- return options.message();
- } else {
- return options.message;
- }
+ return message;
}
} ).on( showEventName, function () {
// Re-add onbeforeunload handler
@@ -60,9 +75,38 @@
}
} );
- // return the function they can use to stop this
- return function () {
- $( window ).off( mainEventName + ' ' + showEventName );
+ /**
+ * Return the object with functions to release and manually trigger the confirm alert
+ *
+ * @ignore
+ */
+ return {
+ /**
+ * Remove all event listeners and don't show an alert anymore, if the user wants to leave
+ * the page.
+ *
+ * @ignore
+ */
+ release: function () {
+ $( window ).off( mainEventName + ' ' + showEventName );
+ },
+ /**
+ * Trigger the module's function manually: Check, if options.test() returns true and show
+ * an alert to the user if he/she want to leave this page. Returns false, if options.test() returns
+ * false or the user cancelled the alert window (~don't leave the page), true otherwise.
+ *
+ * @ignore
+ * @return {boolean}
+ */
+ trigger: function () {
+ // use confirm to show the message to the user (if options.text() is true)
+ if ( options.test() && !confirm( message ) ) {
+ // the user want to keep the actual page
+ return false;
+ }
+ // otherwise return true
+ return true;
+ }
};
};
} )( mediaWiki, jQuery );
diff --git a/resources/src/mediawiki/mediawiki.cookie.js b/resources/src/mediawiki/mediawiki.cookie.js
index 8f091e4d..d260fca6 100644
--- a/resources/src/mediawiki/mediawiki.cookie.js
+++ b/resources/src/mediawiki/mediawiki.cookie.js
@@ -16,7 +16,7 @@
mw.cookie = {
/**
- * Sets or deletes a cookie.
+ * Set or delete a cookie.
*
* While this is natural in JavaScript, contrary to `WebResponse#setcookie` in PHP, the
* default values for the `options` properties only apply if that property isn't set
@@ -101,13 +101,13 @@
},
/**
- * Gets the value of a cookie.
+ * Get the value of a cookie.
*
* @param {string} key
* @param {string} [prefix=wgCookiePrefix] The prefix of the key. If `prefix` is
* `undefined` or `null`, then `wgCookiePrefix` is used
* @param {Mixed} [defaultValue=null]
- * @return {string} If the cookie exists, then the value of the
+ * @return {string|null|Mixed} If the cookie exists, then the value of the
* cookie, otherwise `defaultValue`
*/
get: function ( key, prefix, defaultValue ) {
diff --git a/resources/src/mediawiki/mediawiki.debug.js b/resources/src/mediawiki/mediawiki.debug.js
index bdff99f7..f7210095 100644
--- a/resources/src/mediawiki/mediawiki.debug.js
+++ b/resources/src/mediawiki/mediawiki.debug.js
@@ -222,7 +222,7 @@
className: 'mw-debug-pane',
id: 'mw-debug-pane-' + id
} )
- .append( panes[id] )
+ .append( panes[ id ] )
.appendTo( $container );
}
@@ -255,7 +255,7 @@
};
for ( i = 0, length = this.data.log.length; i < length; i += 1 ) {
- entry = this.data.log[i];
+ entry = this.data.log[ i ];
entry.typeText = entryTypeText( entry.type );
$( '<tr>' )
@@ -289,13 +289,13 @@
.appendTo( $table );
for ( i = 0, length = this.data.queries.length; i < length; i += 1 ) {
- query = this.data.queries[i];
+ query = this.data.queries[ i ];
$( '<tr>' )
.append( $( '<td>' ).text( i + 1 ) )
.append( $( '<td>' ).text( query.sql ) )
.append( $( '<td class="stats">' ).text( ( query.time * 1000 ).toFixed( 4 ) + 'ms' ) )
- .append( $( '<td>' ).text( query['function'] ) )
+ .append( $( '<td>' ).text( query[ 'function' ] ) )
.appendTo( $table );
}
@@ -312,7 +312,7 @@
$list = $( '<ul>' );
for ( i = 0, length = this.data.debugLog.length; i < length; i += 1 ) {
- line = this.data.debugLog[i];
+ line = this.data.debugLog[ i ];
$( '<li>' )
.html( mw.html.escape( line ).replace( /\n/g, '<br />\n' ) )
.appendTo( $list );
@@ -346,7 +346,7 @@
$( '<tr>' )
.append( $( '<th>' ).text( key ) )
- .append( $( '<td>' ).text( data[key] ) )
+ .append( $( '<td>' ).text( data[ key ] ) )
.appendTo( $table );
}
@@ -370,7 +370,7 @@
$table = $( '<table>' );
for ( i = 0, length = this.data.includes.length; i < length; i += 1 ) {
- file = this.data.includes[i];
+ file = this.data.includes[ i ];
$( '<tr>' )
.append( $( '<td>' ).text( file.name ) )
.append( $( '<td class="nr">' ).text( file.size ) )
diff --git a/resources/src/mediawiki/mediawiki.errorLogger.js b/resources/src/mediawiki/mediawiki.errorLogger.js
index 9f4f19dd..46b84797 100644
--- a/resources/src/mediawiki/mediawiki.errorLogger.js
+++ b/resources/src/mediawiki/mediawiki.errorLogger.js
@@ -1,5 +1,6 @@
/**
* Try to catch errors in modules which don't do their own error handling.
+ *
* @class mw.errorLogger
* @singleton
*/
@@ -24,6 +25,7 @@
/**
* Install a window.onerror handler that will report via mw.track, while preserving
* any previous handler.
+ *
* @param {Object} window
*/
installGlobalHandler: function ( window ) {
@@ -35,6 +37,7 @@
/**
* Dumb window.onerror handler which forwards the errors via mw.track.
+ *
* @fires global_error
*/
window.onerror = function ( errorMessage, url, lineNumber, columnNumber, errorObject ) {
diff --git a/resources/src/mediawiki/mediawiki.experiments.js b/resources/src/mediawiki/mediawiki.experiments.js
new file mode 100644
index 00000000..75b1f80d
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.experiments.js
@@ -0,0 +1,110 @@
+/* jshint bitwise:false */
+( function ( mw, $ ) {
+
+ var CONTROL_BUCKET = 'control',
+ MAX_INT32_UNSIGNED = 4294967295;
+
+ /**
+ * An implementation of Jenkins' one-at-a-time hash.
+ *
+ * @see http://en.wikipedia.org/wiki/Jenkins_hash_function
+ *
+ * @param {String} string String to hash
+ * @return {Number} The hash as a 32-bit unsigned integer
+ * @ignore
+ *
+ * @author Ori Livneh <ori@wikimedia.org>
+ * @see http://jsbin.com/kejewi/4/watch?js,console
+ */
+ function hashString( string ) {
+ var hash = 0,
+ i = string.length;
+
+ while ( i-- ) {
+ hash += string.charCodeAt( i );
+ hash += ( hash << 10 );
+ hash ^= ( hash >> 6 );
+ }
+ hash += ( hash << 3 );
+ hash ^= ( hash >> 11 );
+ hash += ( hash << 15 );
+
+ return hash >>> 0;
+ }
+
+ /**
+ * Provides an API for bucketing users in experiments.
+ *
+ * @class mw.experiments
+ * @singleton
+ */
+ mw.experiments = {
+
+ /**
+ * Gets the bucket for the experiment given the token.
+ *
+ * The name of the experiment and the token are hashed. The hash is converted
+ * to a number which is then used to get a bucket.
+ *
+ * Consider the following experiment specification:
+ *
+ * ```
+ * {
+ * name: 'My first experiment',
+ * enabled: true,
+ * buckets: {
+ * control: 0.5
+ * A: 0.25,
+ * B: 0.25
+ * }
+ * }
+ * ```
+ *
+ * The experiment has three buckets: control, A, and B. The user has a 50%
+ * chance of being assigned to the control bucket, and a 25% chance of being
+ * assigned to either the A or B buckets. If the experiment were disabled,
+ * then the user would always be assigned to the control bucket.
+ *
+ * This function is based on the deprecated `mw.user.bucket` function.
+ *
+ * @param {Object} experiment
+ * @param {String} experiment.name The name of the experiment
+ * @param {Boolean} experiment.enabled Whether or not the experiment is
+ * enabled. If the experiment is disabled, then the user is always assigned
+ * to the control bucket
+ * @param {Object} experiment.buckets A map of bucket name to probability
+ * that the user will be assigned to that bucket
+ * @param {String} token A token that uniquely identifies the user for the
+ * duration of the experiment
+ * @returns {String} The bucket
+ */
+ getBucket: function ( experiment, token ) {
+ var buckets = experiment.buckets,
+ key,
+ range = 0,
+ hash,
+ max,
+ acc = 0;
+
+ if ( !experiment.enabled || $.isEmptyObject( experiment.buckets ) ) {
+ return CONTROL_BUCKET;
+ }
+
+ for ( key in buckets ) {
+ range += buckets[ key ];
+ }
+
+ hash = hashString( experiment.name + ':' + token );
+ max = ( hash / MAX_INT32_UNSIGNED ) * range;
+
+ for ( key in buckets ) {
+ acc += buckets[ key ];
+
+ if ( max <= acc ) {
+ return key;
+ }
+ }
+ }
+ };
+
+}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.feedback.js b/resources/src/mediawiki/mediawiki.feedback.js
index d9401001..d226ed9d 100644
--- a/resources/src/mediawiki/mediawiki.feedback.js
+++ b/resources/src/mediawiki/mediawiki.feedback.js
@@ -22,8 +22,8 @@
* dialog box. Submitting that dialog box appends its contents to a
* wiki page that you specify, as a new section.
*
- * This feature works with classic MediaWiki pages
- * and is not compatible with LiquidThreads or Flow.
+ * This feature works with any content model that defines a
+ * `mw.messagePoster.MessagePoster`.
*
* Minimal usage example:
*
@@ -86,6 +86,7 @@
* 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
@@ -199,7 +200,7 @@
*/
mw.Feedback.Dialog = function mwFeedbackDialog( config ) {
// Parent constructor
- mw.Feedback.Dialog.super.call( this, config );
+ mw.Feedback.Dialog.parent.call( this, config );
this.status = '';
this.feedbackPageTitle = null;
@@ -239,7 +240,7 @@
feedbackFieldsetLayout, termsOfUseLabel;
// Parent method
- mw.Feedback.Dialog.super.prototype.initialize.call( this );
+ mw.Feedback.Dialog.parent.prototype.initialize.call( this );
this.feedbackPanel = new OO.ui.PanelLayout( {
scrollable: false,
@@ -329,7 +330,7 @@
* @inheritdoc
*/
mw.Feedback.Dialog.prototype.getSetupProcess = function ( data ) {
- return mw.Feedback.Dialog.super.prototype.getSetupProcess.call( this, data )
+ return mw.Feedback.Dialog.parent.prototype.getSetupProcess.call( this, data )
.next( function () {
var plainMsg, parsedMsg,
settings = data.settings;
@@ -381,7 +382,7 @@
* @inheritdoc
*/
mw.Feedback.Dialog.prototype.getReadyProcess = function ( data ) {
- return mw.Feedback.Dialog.super.prototype.getReadyProcess.call( this, data )
+ return mw.Feedback.Dialog.parent.prototype.getReadyProcess.call( this, data )
.next( function () {
this.feedbackSubjectInput.focus();
}, this );
@@ -431,7 +432,7 @@
}, this );
}
// Fallback to parent handler
- return mw.Feedback.Dialog.super.prototype.getActionProcess.call( this, action );
+ return mw.Feedback.Dialog.parent.prototype.getActionProcess.call( this, action );
};
/**
@@ -472,7 +473,7 @@
* @inheritdoc
*/
mw.Feedback.Dialog.prototype.getTeardownProcess = function ( data ) {
- return mw.Feedback.Dialog.super.prototype.getTeardownProcess.call( this, data )
+ return mw.Feedback.Dialog.parent.prototype.getTeardownProcess.call( this, data )
.first( function () {
this.emit( 'submit', this.status, this.feedbackPageName, this.feedbackPageUrl );
// Cleanup
@@ -486,6 +487,7 @@
/**
* Set the bug report link
+ *
* @param {string} link Link to the external bug report form
*/
mw.Feedback.Dialog.prototype.setBugReportLink = function ( link ) {
@@ -494,6 +496,7 @@
/**
* Get the bug report link
+ *
* @returns {string} Link to the external bug report form
*/
mw.Feedback.Dialog.prototype.getBugReportLink = function () {
diff --git a/resources/src/mediawiki/mediawiki.feedlink.css b/resources/src/mediawiki/mediawiki.feedlink.css
new file mode 100644
index 00000000..a07a4031
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.feedlink.css
@@ -0,0 +1,16 @@
+/* Styles for links to RSS/Atom feeds in sidebar */
+
+a.feedlink {
+ /* 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 */
+ background-image: url(images/feed-icon.png);
+ /* @embed */
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/feed-icon.svg);
+ /* @embed */
+ background-image: linear-gradient(transparent, transparent), url(images/feed-icon.svg);
+ background-position: center left;
+ background-repeat: no-repeat;
+ background-size: 12px 12px;
+ padding-left: 16px;
+}
diff --git a/resources/src/mediawiki/mediawiki.filewarning.less b/resources/src/mediawiki/mediawiki.filewarning.less
index 489ac428..f4af4bae 100644
--- a/resources/src/mediawiki/mediawiki.filewarning.less
+++ b/resources/src/mediawiki/mediawiki.filewarning.less
@@ -1,7 +1,7 @@
-@import "mediawiki.ui/variables"
+@import "mediawiki.ui/variables";
.mediawiki-filewarning {
- display: none;
+ visibility: hidden;
.mediawiki-filewarning-header {
padding: 0;
@@ -17,7 +17,7 @@
}
.mediawiki-filewarning-anchor:hover & {
- display: block;
+ visibility: visible;
}
}
diff --git a/resources/src/mediawiki/mediawiki.htmlform.css b/resources/src/mediawiki/mediawiki.htmlform.css
new file mode 100644
index 00000000..e41248c1
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.htmlform.css
@@ -0,0 +1,51 @@
+/* HTMLForm styles */
+
+table.mw-htmlform-nolabel td.mw-label {
+ width: 1px;
+}
+
+.mw-htmlform-invalid-input td.mw-input input {
+ border-color: red;
+}
+
+.mw-htmlform-flatlist div.mw-htmlform-flatlist-item {
+ display: inline;
+ margin-right: 1em;
+ white-space: nowrap;
+}
+
+/* HTMLCheckMatrix */
+
+.mw-htmlform-matrix td {
+ padding-left: 0.5em;
+ padding-right: 0.5em;
+}
+
+tr.mw-htmlform-vertical-label td.mw-label {
+ text-align: left !important;
+}
+
+.mw-icon-question {
+ /* 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 */
+ background-image: url(images/question.png);
+ /* @embed */
+ background-image: -webkit-linear-gradient(transparent, transparent), url(images/question.svg);
+ /* @embed */
+ background-image: linear-gradient(transparent, transparent), url(images/question.svg);
+ background-repeat: no-repeat;
+ background-size: 13px 13px;
+ display: inline-block;
+ height: 13px;
+ width: 13px;
+ margin-left: 4px;
+}
+
+.mw-icon-question:lang(ar),
+.mw-icon-question:lang(fa),
+.mw-icon-question:lang(ur) {
+ -webkit-transform: scaleX(-1);
+ -ms-transform: scaleX(-1);
+ transform: scaleX(-1);
+}
diff --git a/resources/src/mediawiki/mediawiki.htmlform.js b/resources/src/mediawiki/mediawiki.htmlform.js
index 4a4a97e9..8c6f3ab9 100644
--- a/resources/src/mediawiki/mediawiki.htmlform.js
+++ b/resources/src/mediawiki/mediawiki.htmlform.js
@@ -53,7 +53,7 @@
function hideIfParse( $el, spec ) {
var op, i, l, v, $field, $fields, fields, func, funcs, getVal;
- op = spec[0];
+ op = spec[ 0 ];
l = spec.length;
switch ( op ) {
case 'AND':
@@ -63,12 +63,12 @@
funcs = [];
fields = [];
for ( i = 1; i < l; i++ ) {
- if ( !$.isArray( spec[i] ) ) {
+ if ( !$.isArray( spec[ i ] ) ) {
throw new Error( op + ' parameters must be arrays' );
}
- v = hideIfParse( $el, spec[i] );
- fields = fields.concat( v[0].toArray() );
- funcs.push( v[1] );
+ v = hideIfParse( $el, spec[ i ] );
+ fields = fields.concat( v[ 0 ].toArray() );
+ funcs.push( v[ 1 ] );
}
$fields = $( fields );
@@ -78,7 +78,7 @@
func = function () {
var i;
for ( i = 0; i < l; i++ ) {
- if ( !funcs[i]() ) {
+ if ( !funcs[ i ]() ) {
return false;
}
}
@@ -90,7 +90,7 @@
func = function () {
var i;
for ( i = 0; i < l; i++ ) {
- if ( funcs[i]() ) {
+ if ( funcs[ i ]() ) {
return true;
}
}
@@ -102,7 +102,7 @@
func = function () {
var i;
for ( i = 0; i < l; i++ ) {
- if ( !funcs[i]() ) {
+ if ( !funcs[ i ]() ) {
return true;
}
}
@@ -114,7 +114,7 @@
func = function () {
var i;
for ( i = 0; i < l; i++ ) {
- if ( funcs[i]() ) {
+ if ( funcs[ i ]() ) {
return false;
}
}
@@ -129,12 +129,12 @@
if ( l !== 2 ) {
throw new Error( 'NOT takes exactly one parameter' );
}
- if ( !$.isArray( spec[1] ) ) {
+ if ( !$.isArray( spec[ 1 ] ) ) {
throw new Error( 'NOT parameters must be arrays' );
}
- v = hideIfParse( $el, spec[1] );
- $fields = v[0];
- func = v[1];
+ v = hideIfParse( $el, spec[ 1 ] );
+ $fields = v[ 0 ];
+ func = v[ 1 ];
return [ $fields, function () {
return !func();
} ];
@@ -144,13 +144,13 @@
if ( l !== 3 ) {
throw new Error( op + ' takes exactly two parameters' );
}
- $field = hideIfGetField( $el, spec[1] );
+ $field = hideIfGetField( $el, spec[ 1 ] );
if ( !$field ) {
return [ $(), function () {
return false;
} ];
}
- v = spec[2];
+ v = spec[ 2 ];
if ( $field.first().prop( 'type' ) === 'radio' ||
$field.first().prop( 'type' ) === 'checkbox'
@@ -203,7 +203,7 @@
* jQuery plugin to fade or snap to hiding state.
*
* @param {boolean} [instantToggle=false]
- * @return jQuery
+ * @return {jQuery}
* @chainable
*/
$.fn.goOut = function ( instantToggle ) {
@@ -222,7 +222,7 @@
* @param {Function} callback
* @param {boolean|jQuery.Event} callback.immediate True when the event is called immediately,
* an event object when triggered from an event.
- * @return jQuery
+ * @return {jQuery}
* @chainable
*/
mw.log.deprecate( $.fn, 'liveAndTestAtStart', function ( callback ) {
@@ -304,8 +304,8 @@
}
v = hideIfParse( $el, spec );
- $fields = v[0];
- test = v[1];
+ $fields = v[ 0 ];
+ test = v[ 1 ];
func = function () {
if ( test() ) {
$el.hide();
@@ -413,7 +413,7 @@
$ul = $( this ).prev( 'ul.mw-htmlform-cloner-ul' );
html = $ul.data( 'template' ).replace(
- new RegExp( $.escapeRE( $ul.data( 'uniqueId' ) ), 'g' ),
+ new RegExp( mw.RegExp.escape( $ul.data( 'uniqueId' ) ), 'g' ),
'clone' + ( ++cloneCounter )
);
diff --git a/resources/src/mediawiki/mediawiki.htmlform.ooui.css b/resources/src/mediawiki/mediawiki.htmlform.ooui.css
new file mode 100644
index 00000000..309eb349
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.htmlform.ooui.css
@@ -0,0 +1,31 @@
+/* OOUIHTMLForm styles */
+
+.mw-htmlform-ooui-wrapper {
+ width: 50em;
+ margin: 1em 0;
+}
+
+.oo-ui-fieldLayout.mw-htmlform-ooui-header-empty,
+.oo-ui-fieldLayout.mw-htmlform-ooui-header-empty .oo-ui-fieldLayout-body {
+ display: none;
+}
+
+.oo-ui-fieldLayout.mw-htmlform-ooui-header-errors {
+ /* Override 'display: none' from above */
+ display: block;
+}
+
+.mw-htmlform-ooui .mw-htmlform-submit-buttons {
+ margin-top: 1em;
+}
+
+.mw-htmlform-ooui .mw-htmlform-field-HTMLCheckMatrix,
+.mw-htmlform-ooui .mw-htmlform-matrix,
+.mw-htmlform-ooui .mw-htmlform-matrix tr {
+ width: 100%;
+}
+
+.mw-htmlform-ooui .mw-htmlform-matrix tr td.first {
+ margin-right: 5%;
+ width: 39%;
+}
diff --git a/resources/src/mediawiki/mediawiki.inspect.js b/resources/src/mediawiki/mediawiki.inspect.js
index 22d3cbb3..4859953d 100644
--- a/resources/src/mediawiki/mediawiki.inspect.js
+++ b/resources/src/mediawiki/mediawiki.inspect.js
@@ -13,7 +13,7 @@
function sortByProperty( array, prop, descending ) {
var order = descending ? -1 : 1;
return array.sort( function ( a, b ) {
- return a[prop] > b[prop] ? order : a[prop] < b[prop] ? -order : 0;
+ return a[ prop ] > b[ prop ] ? order : a[ prop ] < b[ prop ] ? -order : 0;
} );
}
@@ -25,7 +25,7 @@
for ( ; bytes >= 1024; bytes /= 1024 ) { i++; }
// Maintain one decimal for kB and above, but don't
// add ".0" for bytes.
- return bytes.toFixed( i > 0 ? 1 : 0 ) + units[i];
+ return bytes.toFixed( i > 0 ? 1 : 0 ) + units[ i ];
}
/**
@@ -45,18 +45,18 @@
graph = {};
$.each( modules, function ( moduleIndex, moduleName ) {
- var dependencies = mw.loader.moduleRegistry[moduleName].dependencies || [];
+ var dependencies = mw.loader.moduleRegistry[ moduleName ].dependencies || [];
if ( !hasOwn.call( graph, moduleName ) ) {
- graph[moduleName] = { requiredBy: [] };
+ graph[ moduleName ] = { requiredBy: [] };
}
- graph[moduleName].requires = dependencies;
+ graph[ moduleName ].requires = dependencies;
$.each( dependencies, function ( depIndex, depName ) {
if ( !hasOwn.call( graph, depName ) ) {
- graph[depName] = { requiredBy: [] };
+ graph[ depName ] = { requiredBy: [] };
}
- graph[depName].requiredBy.push( moduleName );
+ graph[ depName ].requiredBy.push( moduleName );
} );
} );
return graph;
@@ -101,7 +101,7 @@
* document.
*
* @param {string} css CSS source
- * @return Selector counts
+ * @return {Object} Selector counts
* @return {number} return.selectors Total number of selectors
* @return {number} return.matched Number of matched selectors
*/
@@ -117,9 +117,15 @@
rules = sheet.cssRules || sheet.rules;
$.each( rules, function ( index, rule ) {
selectors.total++;
- if ( document.querySelector( rule.selectorText ) !== null ) {
- selectors.matched++;
- }
+ // document.querySelector() on prefixed pseudo-elements can throw exceptions
+ // in Firefox and Safari. Ignore these exceptions.
+ // https://bugs.webkit.org/show_bug.cgi?id=149160
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=1204880
+ try {
+ if ( document.querySelector( rule.selectorText ) !== null ) {
+ selectors.matched++;
+ }
+ } catch ( e ) {}
} );
document.body.removeChild( style );
return selectors;
@@ -173,7 +179,7 @@
$.map( inspect.reports, function ( v, k ) { return k; } );
$.each( reports, function ( index, name ) {
- inspect.dumpTable( inspect.reports[name]() );
+ inspect.dumpTable( inspect.reports[ name ]() );
} );
},
@@ -214,7 +220,7 @@
var modules = [];
$.each( inspect.getLoadedModules(), function ( index, name ) {
- var css, stats, module = mw.loader.moduleRegistry[name];
+ var css, stats, module = mw.loader.moduleRegistry[ name ];
try {
css = module.style.css.join();
@@ -247,7 +253,7 @@
stats.totalSize = humanSize( $.byteLength( raw ) );
} catch ( e ) {}
}
- return [stats];
+ return [ stats ];
}
},
@@ -261,12 +267,11 @@
*/
grep: function ( pattern ) {
if ( typeof pattern.test !== 'function' ) {
- // Based on Y.Escape.regex from YUI v3.15.0
- pattern = new RegExp( pattern.replace( /[\-$\^*()+\[\]{}|\\,.?\s]/g, '\\$&' ), 'g' );
+ pattern = new RegExp( mw.RegExp.escape( pattern ), 'g' );
}
return $.grep( inspect.getLoadedModules(), function ( moduleName ) {
- var module = mw.loader.moduleRegistry[moduleName];
+ var module = mw.loader.moduleRegistry[ moduleName ];
// Grep module's JavaScript
if ( $.isFunction( module.script ) && pattern.test( module.script.toString() ) ) {
diff --git a/resources/src/mediawiki/mediawiki.jqueryMsg.js b/resources/src/mediawiki/mediawiki.jqueryMsg.js
index 79939f64..d179c825 100644
--- a/resources/src/mediawiki/mediawiki.jqueryMsg.js
+++ b/resources/src/mediawiki/mediawiki.jqueryMsg.js
@@ -15,14 +15,12 @@
slice = Array.prototype.slice,
parserDefaults = {
magic: {
- 'SITENAME': mw.config.get( 'wgSiteName' )
+ SITENAME: mw.config.get( 'wgSiteName' )
},
- // This is a whitelist based on, but simpler than, Sanitizer.php.
+ // Whitelist for allowed HTML elements in wikitext.
// Self-closing tags are not currently supported.
- allowedHtmlElements: [
- 'b',
- 'i'
- ],
+ // Can be populated via setPrivateData().
+ allowedHtmlElements: [],
// Key tag name, value allowed attributes for that tag.
// See Sanitizer::setupAttributeWhitelist
allowedHtmlCommonAttributes: [
@@ -62,6 +60,9 @@
* Wrapper around jQuery append that converts all non-objects to TextNode so append will not
* convert what it detects as an htmlString to an element.
*
+ * If our own htmlEmitter jQuery object is given, its children will be unwrapped and appended to
+ * new parent.
+ *
* Object elements of children (jQuery, HTMLElement, TextNode, etc.) will be left as is.
*
* @private
@@ -73,12 +74,15 @@
var i, len;
if ( !$.isArray( children ) ) {
- children = [children];
+ children = [ children ];
}
for ( i = 0, len = children.length; i < len; i++ ) {
- if ( typeof children[i] !== 'object' ) {
- children[i] = document.createTextNode( children[i] );
+ if ( typeof children[ i ] !== 'object' ) {
+ children[ i ] = document.createTextNode( children[ i ] );
+ }
+ if ( children[ i ] instanceof jQuery && children[ i ].hasClass( 'mediaWiki_htmlEmitter' ) ) {
+ children[ i ] = children[ i ].contents();
}
}
@@ -102,11 +106,26 @@
}
/**
+ * Turn input into a string.
+ *
+ * @private
+ * @param {string|jQuery} input
+ * @return {string} Textual value of input
+ */
+ function textify( input ) {
+ if ( input instanceof jQuery ) {
+ input = input.text();
+ }
+ return String( input );
+ }
+
+ /**
* Given parser options, return a function that parses a key and replacements, returning jQuery object
*
* Try to parse a key and optional replacements, returning a jQuery object that may be a tree of jQuery nodes.
* If there was an error parsing, return the key and the error message (wrapped in jQuery). This should put the error right into
* the interface, without causing the page to halt script execution, and it hopefully should be clearer how to fix it.
+ *
* @private
* @param {Object} options Parser options
* @return {Function}
@@ -118,8 +137,8 @@
return function ( args ) {
var fallback,
- key = args[0],
- argsArray = $.isArray( args[1] ) ? args[1] : slice.call( args, 1 );
+ key = args[ 0 ],
+ argsArray = $.isArray( args[ 1 ] ) ? args[ 1 ] : slice.call( args, 1 );
try {
return parser.parse( key, argsArray );
} catch ( e ) {
@@ -133,6 +152,22 @@
mw.jqueryMsg = {};
/**
+ * Initialize parser defaults.
+ *
+ * ResourceLoaderJqueryMsgModule calls this to provide default values from
+ * Sanitizer.php for allowed HTML elements. To override this data for individual
+ * parsers, pass the relevant options to mw.jqueryMsg.parser.
+ *
+ * @private
+ * @param {Object} data
+ */
+ mw.jqueryMsg.setParserDefaults = function ( data ) {
+ if ( data.allowedHtmlElements ) {
+ parserDefaults.allowedHtmlElements = data.allowedHtmlElements;
+ }
+ };
+
+ /**
* Returns a function suitable for use as a global, to construct strings from the message key (and optional replacements).
* e.g.
*
@@ -154,8 +189,7 @@
* @return {string} return.return Rendered HTML.
*/
mw.jqueryMsg.getMessageFunction = function ( options ) {
- var failableParserFn = getFailableParserFn( options ),
- format;
+ var failableParserFn, format;
if ( options && options.format !== undefined ) {
format = options.format;
@@ -164,6 +198,9 @@
}
return function () {
+ if ( !failableParserFn ) {
+ failableParserFn = getFailableParserFn( options );
+ }
var failableResult = failableParserFn( arguments );
if ( format === 'text' || format === 'escaped' ) {
return failableResult.text();
@@ -196,15 +233,14 @@
* @return {jQuery} return.return
*/
mw.jqueryMsg.getPlugin = function ( options ) {
- var failableParserFn = getFailableParserFn( options );
+ var failableParserFn;
return function () {
+ if ( !failableParserFn ) {
+ failableParserFn = getFailableParserFn( options );
+ }
var $target = this.empty();
- // TODO: Simply appendWithoutParsing( $target, failableParserFn( arguments ).contents() )
- // or Simply appendWithoutParsing( $target, failableParserFn( arguments ) )
- $.each( failableParserFn( arguments ).contents(), function ( i, node ) {
- appendWithoutParsing( $target, node );
- } );
+ appendWithoutParsing( $target, failableParserFn( arguments ) );
return $target;
};
};
@@ -226,32 +262,10 @@
mw.jqueryMsg.parser.prototype = {
/**
- * Cache mapping MediaWiki message keys and the value onlyCurlyBraceTransform, to the AST of the message.
- *
- * In most cases, the message is a string so this is identical.
- * (This is why we would like to move this functionality server-side).
- *
- * The two parts of the key are separated by colon. For example:
- *
- * "message-key:true": ast
- *
- * if they key is "message-key" and onlyCurlyBraceTransform is true.
- *
- * This cache is shared by all instances of mw.jqueryMsg.parser.
- *
- * NOTE: We promise, it's static - when you create this empty object
- * in the prototype, each new instance of the class gets a reference
- * to the same object.
- *
- * @static
- * @property {Object}
- */
- astCache: {},
-
- /**
* Where the magic happens.
* Parses a message from the key, and swaps in replacements as necessary, wraps in jQuery
* If an error is thrown, returns original key, and logs the error
+ *
* @param {string} key Message key.
* @param {Array} replacements Variable replacements for $1, $2... $n
* @return {jQuery}
@@ -263,21 +277,16 @@
/**
* Fetch the message string associated with a key, return parsed structure. Memoized.
* Note that we pass '[' + key + ']' back for a missing message here.
+ *
* @param {string} key
* @return {string|Array} string of '[key]' if message missing, simple string if possible, array of arrays if needs parsing
*/
getAst: function ( key ) {
- var wikiText,
- cacheKey = [key, this.settings.onlyCurlyBraceTransform].join( ':' );
-
- if ( this.astCache[ cacheKey ] === undefined ) {
- wikiText = this.settings.messages.get( key );
- if ( typeof wikiText !== 'string' ) {
- wikiText = '\\[' + key + '\\]';
- }
- this.astCache[ cacheKey ] = this.wikiTextToAst( wikiText );
+ var wikiText = this.settings.messages.get( key );
+ if ( typeof wikiText !== 'string' ) {
+ wikiText = '\\[' + key + '\\]';
}
- return this.astCache[ cacheKey ];
+ return this.wikiTextToAst( wikiText );
},
/**
@@ -297,7 +306,7 @@
escapedOrLiteralWithoutSpace, escapedOrLiteralWithoutBar, escapedOrRegularLiteral,
whitespace, dollar, digits, htmlDoubleQuoteAttributeValue, htmlSingleQuoteAttributeValue,
htmlAttributeEquals, openHtmlStartTag, optionalForwardSlash, openHtmlEndTag, closeHtmlTag,
- openExtlink, closeExtlink, wikilinkPage, wikilinkContents, openWikilink, closeWikilink, templateName, pipe, colon,
+ openExtlink, closeExtlink, wikilinkContents, openWikilink, closeWikilink, templateName, pipe, colon,
templateContents, openTemplate, closeTemplate,
nonWhitespaceExpression, paramExpression, expression, curlyBraceTransformExpression, result,
settings = this.settings,
@@ -313,6 +322,7 @@
/**
* Try parsers until one works, if none work return null
+ *
* @private
* @param {Function[]} ps
* @return {string|null}
@@ -321,7 +331,7 @@
return function () {
var i, result;
for ( i = 0; i < ps.length; i++ ) {
- result = ps[i]();
+ result = ps[ i ]();
if ( result !== null ) {
return result;
}
@@ -333,6 +343,7 @@
/**
* Try several ps in a row, all must succeed or return null.
* This is the only eager one.
+ *
* @private
* @param {Function[]} ps
* @return {string|null}
@@ -342,7 +353,7 @@
originalPos = pos,
result = [];
for ( i = 0; i < ps.length; i++ ) {
- res = ps[i]();
+ res = ps[ i ]();
if ( res === null ) {
pos = originalPos;
return null;
@@ -355,6 +366,7 @@
/**
* Run the same parser over and over until it fails.
* Must succeed a minimum of n times or return null.
+ *
* @private
* @param {number} n
* @param {Function} p
@@ -397,6 +409,7 @@
/**
* Just make parsers out of simpler JS builtin types
+ *
* @private
* @param {string} s
* @return {Function}
@@ -429,8 +442,8 @@
if ( matches === null ) {
return null;
}
- pos += matches[0].length;
- return matches[0];
+ pos += matches[ 0 ].length;
+ return matches[ 0 ];
};
}
@@ -470,7 +483,7 @@
backslash,
anyCharacter
] );
- return result === null ? null : result[1];
+ return result === null ? null : result[ 1 ];
}
escapedOrLiteralWithoutSpace = choice( [
escapedLiteral,
@@ -496,13 +509,6 @@
return result === null ? null : result.join( '' );
}
- // Used for wikilink page names. Like literalWithoutBar, but
- // without allowing escapes.
- function unescapedLiteralWithoutBar() {
- var result = nOrMore( 1, regularLiteralWithoutBar )();
- return result === null ? null : result.join( '' );
- }
-
function literal() {
var result = nOrMore( 1, escapedOrRegularLiteral )();
return result === null ? null : result.join( '' );
@@ -529,48 +535,37 @@
if ( result === null ) {
return null;
}
- return [ 'REPLACE', parseInt( result[1], 10 ) - 1 ];
+ return [ 'REPLACE', parseInt( result[ 1 ], 10 ) - 1 ];
}
openExtlink = makeStringParser( '[' );
closeExtlink = makeStringParser( ']' );
// this extlink MUST have inner contents, e.g. [foo] not allowed; [foo bar] [foo <i>bar</i>], etc. are allowed
function extlink() {
- var result, parsedResult;
+ var result, parsedResult, target;
result = null;
parsedResult = sequence( [
openExtlink,
- nonWhitespaceExpression,
+ nOrMore( 1, nonWhitespaceExpression ),
whitespace,
nOrMore( 1, expression ),
closeExtlink
] );
if ( parsedResult !== null ) {
- result = [ 'EXTLINK', parsedResult[1] ];
- // TODO (mattflaschen, 2013-03-22): Clean this up if possible.
- // It's avoiding CONCAT for single nodes, so they at least doesn't get the htmlEmitter span.
- if ( parsedResult[3].length === 1 ) {
- result.push( parsedResult[3][0] );
- } else {
- result.push( ['CONCAT'].concat( parsedResult[3] ) );
- }
+ // When the entire link target is a single parameter, we can't use CONCAT, as we allow
+ // passing fancy parameters (like a whole jQuery object or a function) to use for the
+ // link. Check only if it's a single match, since we can either do CONCAT or not for
+ // singles with the same effect.
+ target = parsedResult[ 1 ].length === 1 ?
+ parsedResult[ 1 ][ 0 ] :
+ [ 'CONCAT' ].concat( parsedResult[ 1 ] );
+ result = [
+ 'EXTLINK',
+ target,
+ [ 'CONCAT' ].concat( parsedResult[ 3 ] )
+ ];
}
return result;
}
- // this is the same as the above extlink, except that the url is being passed on as a parameter
- function extLinkParam() {
- var result = sequence( [
- openExtlink,
- dollar,
- digits,
- whitespace,
- expression,
- closeExtlink
- ] );
- if ( result === null ) {
- return null;
- }
- return [ 'EXTLINKPARAM', parseInt( result[2], 10 ) - 1, result[4] ];
- }
openWikilink = makeStringParser( '[[' );
closeWikilink = makeStringParser( ']]' );
pipe = makeStringParser( '|' );
@@ -581,26 +576,33 @@
templateContents,
closeTemplate
] );
- return result === null ? null : result[1];
+ return result === null ? null : result[ 1 ];
}
- wikilinkPage = choice( [
- unescapedLiteralWithoutBar,
- template
- ] );
-
function pipedWikilink() {
var result = sequence( [
- wikilinkPage,
+ nOrMore( 1, paramExpression ),
pipe,
- expression
+ nOrMore( 1, expression )
+ ] );
+ return result === null ? null : [
+ [ 'CONCAT' ].concat( result[ 0 ] ),
+ [ 'CONCAT' ].concat( result[ 2 ] )
+ ];
+ }
+
+ function unpipedWikilink() {
+ var result = sequence( [
+ nOrMore( 1, paramExpression )
] );
- return result === null ? null : [ result[0], result[2] ];
+ return result === null ? null : [
+ [ 'CONCAT' ].concat( result[ 0 ] )
+ ];
}
wikilinkContents = choice( [
pipedWikilink,
- wikilinkPage // unpiped link
+ unpipedWikilink
] );
function wikilink() {
@@ -613,7 +615,7 @@
closeWikilink
] );
if ( parsedResult !== null ) {
- parsedLinkContents = parsedResult[1];
+ parsedLinkContents = parsedResult[ 1 ];
result = [ 'WIKILINK' ].concat( parsedLinkContents );
}
return result;
@@ -626,7 +628,7 @@
htmlDoubleQuoteAttributeValue,
doubleQuote
] );
- return parsedResult === null ? null : parsedResult[1];
+ return parsedResult === null ? null : parsedResult[ 1 ];
}
function singleQuotedHtmlAttributeValue() {
@@ -635,7 +637,7 @@
htmlSingleQuoteAttributeValue,
singleQuote
] );
- return parsedResult === null ? null : parsedResult[1];
+ return parsedResult === null ? null : parsedResult[ 1 ];
}
function htmlAttribute() {
@@ -648,7 +650,7 @@
singleQuotedHtmlAttributeValue
] )
] );
- return parsedResult === null ? null : [parsedResult[1], parsedResult[3]];
+ return parsedResult === null ? null : [ parsedResult[ 1 ], parsedResult[ 3 ] ];
}
/**
@@ -670,9 +672,9 @@
}
for ( i = 0, len = attributes.length; i < len; i += 2 ) {
- attributeName = attributes[i];
+ attributeName = attributes[ i ];
if ( $.inArray( attributeName, settings.allowedHtmlCommonAttributes ) === -1 &&
- $.inArray( attributeName, settings.allowedHtmlAttributesByElement[startTagName] || [] ) === -1 ) {
+ $.inArray( attributeName, settings.allowedHtmlAttributesByElement[ startTagName ] || [] ) === -1 ) {
return false;
}
}
@@ -683,7 +685,7 @@
function htmlAttributes() {
var parsedResult = nOrMore( 0, htmlAttribute )();
// Un-nest attributes array due to structure of jQueryMsg operations (see emit).
- return concat.apply( ['HTMLATTRIBUTES'], parsedResult );
+ return concat.apply( [ 'HTMLATTRIBUTES' ], parsedResult );
}
// Subset of allowed HTML markup.
@@ -714,7 +716,7 @@
}
endOpenTagPos = pos;
- startTagName = parsedOpenTagResult[1];
+ startTagName = parsedOpenTagResult[ 1 ];
parsedHtmlContents = nOrMore( 0, expression )();
@@ -732,8 +734,8 @@
}
endCloseTagPos = pos;
- endTagName = parsedCloseTagResult[1];
- wrappedAttributes = parsedOpenTagResult[2];
+ endTagName = parsedCloseTagResult[ 1 ];
+ wrappedAttributes = parsedOpenTagResult[ 2 ];
attributes = wrappedAttributes.slice( 1 );
if ( isAllowedHtml( startTagName, endTagName, attributes ) ) {
result = [ 'HTMLELEMENT', startTagName, wrappedAttributes ]
@@ -773,9 +775,9 @@
if ( result === null ) {
return null;
}
- expr = result[1];
+ expr = result[ 1 ];
// use a CONCAT operator if there are multiple nodes, otherwise return the first node, raw.
- return expr.length > 1 ? [ 'CONCAT' ].concat( expr ) : expr[0];
+ return expr.length > 1 ? [ 'CONCAT' ].concat( expr ) : expr[ 0 ];
}
function templateWithReplacement() {
@@ -784,7 +786,7 @@
colon,
replacement
] );
- return result === null ? null : [ result[0], result[2] ];
+ return result === null ? null : [ result[ 0 ], result[ 2 ] ];
}
function templateWithOutReplacement() {
var result = sequence( [
@@ -792,14 +794,14 @@
colon,
paramExpression
] );
- return result === null ? null : [ result[0], result[2] ];
+ return result === null ? null : [ result[ 0 ], result[ 2 ] ];
}
function templateWithOutFirstParameter() {
var result = sequence( [
templateName,
colon
] );
- return result === null ? null : [ result[0], '' ];
+ return result === null ? null : [ result[ 0 ], '' ];
}
colon = makeStringParser( ':' );
templateContents = choice( [
@@ -810,7 +812,7 @@
choice( [ templateWithReplacement, templateWithOutReplacement, templateWithOutFirstParameter ] ),
nOrMore( 0, templateParam )
] );
- return res === null ? null : res[0].concat( res[1] );
+ return res === null ? null : res[ 0 ].concat( res[ 1 ] );
},
function () {
var res = sequence( [
@@ -820,7 +822,7 @@
if ( res === null ) {
return null;
}
- return [ res[0] ].concat( res[1] );
+ return [ res[ 0 ] ].concat( res[ 1 ] );
}
] );
openTemplate = makeStringParser( '{{' );
@@ -828,7 +830,6 @@
nonWhitespaceExpression = choice( [
template,
wikilink,
- extLinkParam,
extlink,
replacement,
literalWithoutSpace
@@ -836,7 +837,6 @@
paramExpression = choice( [
template,
wikilink,
- extLinkParam,
extlink,
replacement,
literalWithoutBar
@@ -845,7 +845,6 @@
expression = choice( [
template,
wikilink,
- extLinkParam,
extlink,
replacement,
html,
@@ -876,7 +875,6 @@
// I am deferring the work of turning it into prototypes & objects. It's quite fast enough
// finally let's do some actual work...
- // If you add another possible rootExpression, you must update the astCache key scheme.
result = start( this.settings.onlyCurlyBraceTransform ? curlyBraceTransformExpression : expression );
/*
@@ -907,6 +905,7 @@
/**
* (We put this method definition here, and not in prototype, to make sure it's not overwritten by any magic.)
* Walk entire node structure, applying replacements and template functions when appropriate
+ *
* @param {Mixed} node Abstract syntax tree (top node or subnode)
* @param {Array} replacements for $1, $2, ... $n
* @return {Mixed} single-string node or array of nodes suitable for jQuery appending
@@ -925,8 +924,8 @@
subnodes = $.map( node.slice( 1 ), function ( n ) {
return jmsg.emit( n, replacements );
} );
- operation = node[0].toLowerCase();
- if ( typeof jmsg[operation] === 'function' ) {
+ operation = node[ 0 ].toLowerCase();
+ if ( typeof jmsg[ operation ] === 'function' ) {
ret = jmsg[ operation ]( subnodes, replacements );
} else {
throw new Error( 'Unknown operation "' + operation + '"' );
@@ -956,21 +955,16 @@
* Parsing has been applied depth-first we can assume that all nodes here are single nodes
* Must return a single node to parents -- a jQuery with synthetic span
* However, unwrap any other synthetic spans in our children and pass them upwards
+ *
* @param {Mixed[]} nodes Some single nodes, some arrays of nodes
* @return {jQuery}
*/
concat: function ( nodes ) {
var $span = $( '<span>' ).addClass( 'mediaWiki_htmlEmitter' );
$.each( nodes, function ( i, node ) {
- if ( node instanceof jQuery && node.hasClass( 'mediaWiki_htmlEmitter' ) ) {
- $.each( node.contents(), function ( j, childNode ) {
- appendWithoutParsing( $span, childNode );
- } );
- } else {
- // Let jQuery append nodes, arrays of nodes and jQuery objects
- // other things (strings, numbers, ..) are appended as text nodes (not as HTML strings)
- appendWithoutParsing( $span, node );
- }
+ // Let jQuery append nodes, arrays of nodes and jQuery objects
+ // other things (strings, numbers, ..) are appended as text nodes (not as HTML strings)
+ appendWithoutParsing( $span, node );
} );
return $span;
},
@@ -988,10 +982,10 @@
* @return {String} replacement
*/
replace: function ( nodes, replacements ) {
- var index = parseInt( nodes[0], 10 );
+ var index = parseInt( nodes[ 0 ], 10 );
if ( index < replacements.length ) {
- return replacements[index];
+ return replacements[ index ];
} else {
// index not found, fallback to displaying variable
return '$' + ( index + 1 );
@@ -1010,12 +1004,17 @@
* from the server, since the replacement is done at save time.
* It may, though, if the wikitext appears in extension-controlled content.
*
- * @param nodes
+ * @param {String[]} nodes
*/
wikilink: function ( nodes ) {
- var page, anchor, url;
+ var page, anchor, url, $el;
- page = nodes[0];
+ page = textify( nodes[ 0 ] );
+ // Strip leading ':', which is used to suppress special behavior in wikitext links,
+ // e.g. [[:Category:Foo]] or [[:File:Foo.jpg]]
+ if ( page.charAt( 0 ) === ':' ) {
+ page = page.slice( 1 );
+ }
url = mw.util.getUrl( page );
if ( nodes.length === 1 ) {
@@ -1023,13 +1022,14 @@
anchor = page;
} else {
// [[Some Page|anchor text]] or [[Namespace:Some Page|anchor]]
- anchor = nodes[1];
+ anchor = nodes[ 1 ];
}
- return $( '<a>' ).attr( {
+ $el = $( '<a>' ).attr( {
title: page,
href: url
- } ).text( anchor );
+ } );
+ return appendWithoutParsing( $el, anchor );
},
/**
@@ -1042,7 +1042,7 @@
htmlattributes: function ( nodes ) {
var i, len, mapping = {};
for ( i = 0, len = nodes.length; i < len; i += 2 ) {
- mapping[nodes[i]] = decodePrimaryHtmlEntities( nodes[i + 1] );
+ mapping[ nodes[ i ] ] = decodePrimaryHtmlEntities( nodes[ i + 1 ] );
}
return mapping;
},
@@ -1064,11 +1064,12 @@
},
/**
- * Transform parsed structure into external link
- * If the href is a jQuery object, treat it as "enclosing" the link text.
+ * Transform parsed structure into external link.
*
- * - ... function, treat it as the click handler.
- * - ... string, treat it as a URI.
+ * The "href" can be:
+ * - a jQuery object, treat it as "enclosing" the link text.
+ * - a function, treat it as the click handler.
+ * - a string, or our htmlEmitter jQuery object, treat it as a URI after stringifying.
*
* TODO: throw an error if nodes.length > 2 ?
*
@@ -1077,9 +1078,9 @@
*/
extlink: function ( nodes ) {
var $el,
- arg = nodes[0],
- contents = nodes[1];
- if ( arg instanceof jQuery ) {
+ arg = nodes[ 0 ],
+ contents = nodes[ 1 ];
+ if ( arg instanceof jQuery && !arg.hasClass( 'mediaWiki_htmlEmitter' ) ) {
$el = arg;
} else {
$el = $( '<a>' );
@@ -1090,39 +1091,17 @@
} )
.click( arg );
} else {
- $el.attr( 'href', arg.toString() );
+ $el.attr( 'href', textify( arg ) );
}
}
return appendWithoutParsing( $el, contents );
},
/**
- * This is basically use a combination of replace + external link (link with parameter
- * as url), but we don't want to run the regular replace here-on: inserting a
- * url as href-attribute of a link will automatically escape it already, so
- * we don't want replace to (manually) escape it as well.
- *
- * TODO: throw error if nodes.length > 1 ?
- *
- * @param {Array} nodes List of one element, integer, n >= 0
- * @param {Array} replacements List of at least n strings
- * @return {string} replacement
- */
- extlinkparam: function ( nodes, replacements ) {
- var replacement,
- index = parseInt( nodes[0], 10 );
- if ( index < replacements.length ) {
- replacement = replacements[index];
- } else {
- replacement = '$' + ( index + 1 );
- }
- return this.extlink( [ replacement, nodes[1] ] );
- },
-
- /**
* Transform parsed structure into pluralization
* n.b. The first node may be a non-integer (for instance, a string representing an Arabic number).
* So convert it back with the current language's convertNumber.
+ *
* @param {Array} nodes List of nodes, [ {string|number}, {string}, {string} ... ]
* @return {string} selected pluralized form according to current language
*/
@@ -1130,30 +1109,30 @@
var forms, firstChild, firstChildText, explicitPluralFormNumber, formIndex, form, count,
explicitPluralForms = {};
- count = parseFloat( this.language.convertNumber( nodes[0], true ) );
+ count = parseFloat( this.language.convertNumber( nodes[ 0 ], true ) );
forms = nodes.slice( 1 );
for ( formIndex = 0; formIndex < forms.length; formIndex++ ) {
- form = forms[formIndex];
+ form = forms[ formIndex ];
- if ( form.jquery && form.hasClass( 'mediaWiki_htmlEmitter' ) ) {
+ if ( form instanceof 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 );
+ 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;
+ 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;
+ explicitPluralFormNumber = parseInt( form.split( /=/ )[ 0 ], 10 );
+ explicitPluralForms[ explicitPluralFormNumber ] = form.slice( form.indexOf( '=' ) + 1 );
+ forms[ formIndex ] = undefined;
}
}
@@ -1180,7 +1159,7 @@
*/
gender: function ( nodes ) {
var gender,
- maybeUser = nodes[0],
+ maybeUser = nodes[ 0 ],
forms = nodes.slice( 1 );
if ( maybeUser === '' ) {
@@ -1201,35 +1180,39 @@
/**
* Transform parsed structure into grammar conversion.
* Invoked by putting `{{grammar:form|word}}` in a message
+ *
* @param {Array} nodes List of nodes [{Grammar case eg: genitive}, {string word}]
* @return {string} selected grammatical form according to current language
*/
grammar: function ( nodes ) {
- var form = nodes[0],
- word = nodes[1];
+ var form = nodes[ 0 ],
+ word = nodes[ 1 ];
return word && form && this.language.convertGrammar( word, form );
},
/**
* Tranform parsed structure into a int: (interface language) message include
* Invoked by putting `{{int:othermessage}}` into a message
+ *
* @param {Array} nodes List of nodes
* @return {string} Other message
*/
'int': function ( nodes ) {
- return mw.jqueryMsg.getMessageFunction()( nodes[0].toLowerCase() );
+ var msg = nodes[ 0 ];
+ return mw.jqueryMsg.getMessageFunction()( msg.charAt( 0 ).toLowerCase() + msg.slice( 1 ) );
},
/**
* Takes an unformatted number (arab, no group separators and . as decimal separator)
* and outputs it in the localized digit script and formatted with decimal
* separator, according to the current language.
+ *
* @param {Array} nodes List of nodes
* @return {number|string} Formatted number
*/
formatnum: function ( nodes ) {
- var isInteger = ( nodes[1] && nodes[1] === 'R' ) ? true : false,
- number = nodes[0];
+ var isInteger = ( nodes[ 1 ] && nodes[ 1 ] === 'R' ) ? true : false,
+ number = nodes[ 0 ];
return this.language.convertNumber( number, isInteger );
}
@@ -1264,9 +1247,9 @@
}
messageFunction = mw.jqueryMsg.getMessageFunction( {
- 'messages': this.map,
+ messages: this.map,
// For format 'escaped', escaping part is handled by mediawiki.js
- 'format': this.format
+ format: this.format
} );
return messageFunction( this.key, this.parameters );
};
diff --git a/resources/src/mediawiki/mediawiki.js b/resources/src/mediawiki/mediawiki.js
index ee57c21f..9436dbf2 100644
--- a/resources/src/mediawiki/mediawiki.js
+++ b/resources/src/mediawiki/mediawiki.js
@@ -7,6 +7,8 @@
* @alternateClassName mediaWiki
* @singleton
*/
+/*jshint latedef:false */
+/*global sha1 */
( function ( $ ) {
'use strict';
@@ -14,6 +16,7 @@
hasOwn = Object.prototype.hasOwnProperty,
slice = Array.prototype.slice,
trackCallbacks = $.Callbacks( 'memory' ),
+ trackHandlers = [],
trackQueue = [];
/**
@@ -66,7 +69,7 @@
if ( $.isPlainObject( selection ) ) {
for ( s in selection ) {
- setGlobalMapValue( this, s, selection[s] );
+ setGlobalMapValue( this, s, selection[ s ] );
}
return true;
}
@@ -93,13 +96,13 @@
* @param {Mixed} value
*/
function setGlobalMapValue( map, key, value ) {
- map.values[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.'
+ window,
+ key,
+ value,
+ // Deprecation notice for mw.config globals (T58550, T72470)
+ map === mw.config && 'Use mw.config instead.'
);
}
@@ -126,7 +129,7 @@
selection = slice.call( selection );
results = {};
for ( i = 0; i < selection.length; i++ ) {
- results[selection[i]] = this.get( selection[i], fallback );
+ results[ selection[ i ] ] = this.get( selection[ i ], fallback );
}
return results;
}
@@ -135,7 +138,7 @@
if ( !hasOwn.call( this.values, selection ) ) {
return fallback;
}
- return this.values[selection];
+ return this.values[ selection ];
}
if ( selection === undefined ) {
@@ -158,12 +161,12 @@
if ( $.isPlainObject( selection ) ) {
for ( s in selection ) {
- this.values[s] = selection[s];
+ this.values[ s ] = selection[ s ];
}
return true;
}
if ( typeof selection === 'string' && arguments.length > 1 ) {
- this.values[selection] = value;
+ this.values[ selection ] = value;
return true;
}
return false;
@@ -180,7 +183,7 @@
if ( $.isArray( selection ) ) {
for ( s = 0; s < selection.length; s++ ) {
- if ( typeof selection[s] !== 'string' || !hasOwn.call( this.values, selection[s] ) ) {
+ if ( typeof selection[ s ] !== 'string' || !hasOwn.call( this.values, selection[ s ] ) ) {
return false;
}
}
@@ -282,7 +285,7 @@
params: function ( parameters ) {
var i;
for ( i = 0; i < parameters.length; i += 1 ) {
- this.parameters.push( parameters[i] );
+ this.parameters.push( parameters[ i ] );
}
return this;
},
@@ -420,7 +423,7 @@
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;
+ return parameters[ index ] !== undefined ? parameters[ index ] : '$' + match;
} );
},
@@ -461,8 +464,7 @@
*/
trackSubscribe: function ( topic, callback ) {
var seen = 0;
-
- trackCallbacks.add( function ( trackQueue ) {
+ function handler( trackQueue ) {
var event;
for ( ; seen < trackQueue.length; seen++ ) {
event = trackQueue[ seen ];
@@ -470,6 +472,26 @@
callback.call( event, event.topic, event.data );
}
}
+ }
+
+ trackHandlers.push( [ handler, callback ] );
+
+ trackCallbacks.add( handler );
+ },
+
+ /**
+ * Stop handling events for a particular handler
+ *
+ * @param {Function} callback
+ */
+ trackUnsubscribe: function ( callback ) {
+ trackHandlers = $.grep( trackHandlers, function ( fns ) {
+ if ( fns[ 1 ] === callback ) {
+ trackCallbacks.remove( fns[ 0 ] );
+ // Ensure the tuple is removed to avoid holding on to closures
+ return false;
+ }
+ return true;
} );
},
@@ -560,6 +582,7 @@
/**
* Dummy placeholder for {@link mw.log}
+ *
* @method
*/
log: ( function () {
@@ -574,7 +597,6 @@
/**
* Write a message the console's warning channel.
- * Also logs a stacktrace for easier debugging.
* Actions not supported by the browser console are silently ignored.
*
* @param {string...} msg Messages to output to console
@@ -583,9 +605,22 @@
var console = window.console;
if ( console && console.warn && console.warn.apply ) {
console.warn.apply( console, arguments );
- if ( console.trace ) {
- console.trace();
- }
+ }
+ };
+
+ /**
+ * Write a message the console's error channel.
+ *
+ * Most browsers provide a stacktrace by default if the argument
+ * is a caught Error object.
+ *
+ * @since 1.26
+ * @param {Error|string...} msg Messages to output to console
+ */
+ log.error = function () {
+ var console = window.console;
+ if ( console && console.error && console.error.apply ) {
+ console.error.apply( console, arguments );
}
};
@@ -599,7 +634,7 @@
* @param {string} [msg] Optional text to include in the deprecation message
*/
log.deprecate = !Object.defineProperty ? function ( obj, key, val ) {
- obj[key] = val;
+ obj[ key ] = val;
} : function ( obj, key, val, msg ) {
msg = 'Use of "' + key + '" is deprecated.' + ( msg ? ( ' ' + msg ) : '' );
// Support: IE8
@@ -621,7 +656,7 @@
} );
} catch ( err ) {
// Fallback to creating a copy of the value to the object.
- obj[key] = val;
+ obj[ key ] = val;
}
};
@@ -678,28 +713,54 @@
/**
* Mapping of registered modules.
*
- * See #implement for exact details on support for script, style and messages.
+ * See #implement and #execute for exact details on support for script, style and messages.
*
* Format:
*
* {
* 'moduleName': {
- * // From startup mdoule
- * 'version': ############## (unix timestamp)
+ * // From mw.loader.register()
+ * 'version': '########' (hash)
* 'dependencies': ['required.foo', 'bar.also', ...], (or) function () {}
* 'group': 'somegroup', (or) null
* 'source': 'local', (or) 'anotherwiki'
* 'skip': 'return !!window.Example', (or) null
+ *
+ * // Set from execute() or mw.loader.state()
* 'state': 'registered', 'loaded', 'loading', 'ready', 'error', or 'missing'
*
- * // Added during implementation
+ * // Optionally added at run-time by mw.loader.implement()
* 'skipped': true
- * 'script': ...
- * 'style': ...
- * 'messages': { 'key': 'value' }
+ * 'script': closure, array of urls, or string
+ * 'style': { ... } (see #execute)
+ * 'messages': { 'key': 'value', ... }
* }
* }
*
+ * State machine:
+ *
+ * - `registered`:
+ * The module is known to the system but not yet requested.
+ * Meta data is registered via mw.loader#register. Calls to that method are
+ * generated server-side by the startup module.
+ * - `loading`:
+ * The module is requested through mw.loader (either directly or as dependency of
+ * another module). The client will be fetching module contents from the server.
+ * The contents are then stashed in the registry via mw.loader#implement.
+ * - `loaded`:
+ * The module has been requested from the server and stashed via mw.loader#implement.
+ * If the module has no more dependencies in-fight, the module will be executed
+ * right away. Otherwise execution is deferred, controlled via #handlePending.
+ * - `executing`:
+ * The module is being executed.
+ * - `ready`:
+ * The module has been successfully executed.
+ * - `error`:
+ * The module (or one of its dependencies) produced an error during execution.
+ * - `missing`:
+ * The module was registered client-side and requested, but the server denied knowledge
+ * of the module's existence.
+ *
* @property
* @private
*/
@@ -720,7 +781,25 @@
// List of modules to be loaded
queue = [],
- // List of callback functions waiting for modules to be ready to be called
+ /**
+ * List of callback jobs waiting for modules to be ready.
+ *
+ * Jobs are created by #request() and run by #handlePending().
+ *
+ * Typically when a job is created for a module, the job's dependencies contain
+ * both the module being requested and all its recursive dependencies.
+ *
+ * Format:
+ *
+ * {
+ * 'dependencies': [ module names ],
+ * 'ready': Function callback
+ * 'error': Function callback
+ * }
+ *
+ * @property {Object[]} jobs
+ * @private
+ */
jobs = [],
// Selector cache for the marker element. Use getMarker() to get/use the marker!
@@ -760,7 +839,7 @@
if ( nextnode ) {
$( nextnode ).before( s );
} else {
- document.getElementsByTagName( 'head' )[0].appendChild( s );
+ document.getElementsByTagName( 'head' )[ 0 ].appendChild( s );
}
if ( s.styleSheet ) {
// Support: IE6-10
@@ -784,7 +863,15 @@
* @param {Function} [callback]
*/
function addEmbeddedCSS( cssText, callback ) {
- var $style, styleEl;
+ var $style, styleEl, newCssText;
+
+ function fireCallbacks() {
+ var oldCallbacks = cssCallbacks;
+ // Reset cssCallbacks variable so it's not polluted by any calls to
+ // addEmbeddedCSS() from one of the callbacks (T105973)
+ cssCallbacks = $.Callbacks();
+ oldCallbacks.fire().empty();
+ }
if ( callback ) {
cssCallbacks.add( callback );
@@ -837,149 +924,61 @@
// 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 ) {
+ if ( $style.data( 'ResourceLoaderDynamicStyleTag' ) ) {
// There's already a dynamic <style> tag present and
// we are able to append more to it.
styleEl = $style.get( 0 );
// Support: IE6-10
if ( styleEl.styleSheet ) {
try {
- styleEl.styleSheet.cssText += cssText;
+ // Support: IE9
+ // We can't do styleSheet.cssText += cssText, since IE9 mangles this property on
+ // write, dropping @media queries from the CSS text. If we read it and used its
+ // value, we would accidentally apply @media-specific styles to all media. (T108727)
+ if ( document.documentMode === 9 ) {
+ newCssText = $style.data( 'ResourceLoaderDynamicStyleTag' ) + cssText;
+ styleEl.styleSheet.cssText = newCssText;
+ $style.data( 'ResourceLoaderDynamicStyleTag', newCssText );
+ } else {
+ styleEl.styleSheet.cssText += cssText;
+ }
} catch ( e ) {
mw.track( 'resourceloader.exception', { exception: e, source: 'stylesheet' } );
}
} else {
styleEl.appendChild( document.createTextNode( cssText ) );
}
- cssCallbacks.fire().empty();
+ fireCallbacks();
return;
}
}
- $( newStyleTag( cssText, getMarker() ) ).data( 'ResourceLoaderDynamicStyleTag', true );
-
- cssCallbacks.fire().empty();
- }
-
- /**
- * 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();
- d.setTime( timestamp * 1000 );
- return [
- pad( d.getUTCFullYear(), d.getUTCMonth() + 1, d.getUTCDate() ),
- 'T',
- pad( d.getUTCHours(), d.getUTCMinutes(), d.getUTCSeconds() ),
- 'Z'
- ].join( '' );
- }
-
- /**
- * Resolve dependencies and detect circular references.
- *
- * @private
- * @param {string} module Name of the top-level module whose dependencies shall be
- * 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.
- * @param {Object} [unresolved] Hash used to track the current dependency
- * 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 ( !hasOwn.call( registry, module ) ) {
- throw new Error( 'Unknown dependency: ' + module );
- }
-
- if ( registry[module].skip !== null ) {
- /*jshint evil:true */
- skip = new Function( registry[module].skip );
- registry[module].skip = null;
- if ( skip() ) {
- registry[module].skipped = true;
- registry[module].dependencies = [];
- registry[module].state = 'ready';
- handlePending( module );
- return;
- }
- }
+ $style = $( newStyleTag( cssText, getMarker() ) );
- // Resolves dynamic loader function and replaces it with its own results
- if ( $.isFunction( registry[module].dependencies ) ) {
- registry[module].dependencies = registry[module].dependencies();
- // Ensures the module's dependencies are always in an array
- if ( typeof registry[module].dependencies !== 'object' ) {
- registry[module].dependencies = [registry[module].dependencies];
- }
- }
- if ( $.inArray( module, resolved ) !== -1 ) {
- // Module already resolved; nothing to do
- return;
- }
- // Create unresolved if not passed in
- if ( !unresolved ) {
- unresolved = {};
+ if ( document.documentMode === 9 ) {
+ // Support: IE9
+ // Preserve original CSS text because IE9 mangles it on write
+ $style.data( 'ResourceLoaderDynamicStyleTag', cssText );
+ } else {
+ $style.data( 'ResourceLoaderDynamicStyleTag', true );
}
- // Tracks down dependencies
- deps = registry[module].dependencies;
- len = deps.length;
- for ( n = 0; n < len; n += 1 ) {
- if ( $.inArray( deps[n], resolved ) === -1 ) {
- if ( unresolved[deps[n]] ) {
- throw new Error(
- 'Circular reference detected: ' + module +
- ' -> ' + deps[n]
- );
- }
- // Add to unresolved
- unresolved[module] = true;
- sortDependencies( deps[n], resolved, unresolved );
- delete unresolved[module];
- }
- }
- resolved[resolved.length] = module;
+ fireCallbacks();
}
/**
- * Get a list of module names that a module depends on in their proper dependency
- * order.
- *
- * @private
- * @param {string[]} module Array of string module names
- * @return {Array} List of dependencies, including 'module'.
+ * @since 1.26
+ * @param {Array} modules List of module names
+ * @return {string} Hash of concatenated version hashes.
*/
- function resolve( modules ) {
- var resolved = [];
- $.each( modules, function ( idx, module ) {
- sortDependencies( module, resolved );
+ function getCombinedVersion( modules ) {
+ var hashes = $.map( modules, function ( module ) {
+ return registry[ module ].version;
} );
- return resolved;
+ // Trim for consistency with server-side ResourceLoader::makeHash. It also helps
+ // save precious space in the limited query string. Otherwise modules are more
+ // likely to require multiple HTTP requests.
+ return sha1( hashes.join( '' ) ).slice( 0, 12 );
}
/**
@@ -993,7 +992,7 @@
function allReady( modules ) {
var i;
for ( i = 0; i < modules.length; i++ ) {
- if ( mw.loader.getState( modules[i] ) !== 'ready' ) {
+ if ( mw.loader.getState( modules[ i ] ) !== 'ready' ) {
return false;
}
}
@@ -1011,7 +1010,7 @@
function anyFailed( modules ) {
var i, state;
for ( i = 0; i < modules.length; i++ ) {
- state = mw.loader.getState( modules[i] );
+ state = mw.loader.getState( modules[ i ] );
if ( state === 'error' || state === 'missing' ) {
return true;
}
@@ -1033,16 +1032,16 @@
function handlePending( module ) {
var j, job, hasErrors, m, stateChange;
- if ( registry[module].state === 'error' || registry[module].state === 'missing' ) {
+ 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 ( registry[m].state !== 'error' && registry[m].state !== 'missing' ) {
- if ( anyFailed( registry[m].dependencies ) ) {
- registry[m].state = 'error';
+ if ( registry[ m ].state !== 'error' && registry[ m ].state !== 'missing' ) {
+ if ( anyFailed( registry[ m ].dependencies ) ) {
+ registry[ m ].state = 'error';
stateChange = true;
}
}
@@ -1052,16 +1051,16 @@
// 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 = anyFailed( jobs[j].dependencies );
- if ( hasErrors || allReady( jobs[j].dependencies ) ) {
+ hasErrors = anyFailed( jobs[ j ].dependencies );
+ if ( hasErrors || allReady( jobs[ j ].dependencies ) ) {
// All dependencies satisfied, or some have errors
- job = jobs[j];
+ job = jobs[ j ];
jobs.splice( j, 1 );
j -= 1;
try {
if ( hasErrors ) {
if ( $.isFunction( job.error ) ) {
- job.error( new Error( 'Module ' + module + ' has failed dependencies' ), [module] );
+ job.error( new Error( 'Module ' + module + ' has failed dependencies' ), [ module ] );
}
} else {
if ( $.isFunction( job.ready ) ) {
@@ -1076,12 +1075,12 @@
}
}
- if ( registry[module].state === 'ready' ) {
+ if ( registry[ module ].state === 'ready' ) {
// The current module became 'ready'. Set it in the module store, and recursively execute all
// dependent modules that are loaded and now have all dependencies satisfied.
- mw.loader.store.set( module, registry[module] );
+ mw.loader.store.set( module, registry[ module ] );
for ( m in registry ) {
- if ( registry[m].state === 'loaded' && allReady( registry[m].dependencies ) ) {
+ if ( registry[ m ].state === 'loaded' && allReady( registry[ m ].dependencies ) ) {
execute( m );
}
}
@@ -1089,39 +1088,130 @@
}
/**
- * Adds a script tag to the DOM, either using document.write or low-level DOM manipulation,
- * depending on whether document-ready has occurred yet and whether we are in async mode.
+ * Resolve dependencies and detect circular references.
*
* @private
- * @param {string} src URL to script, will be used as the src attribute in the script tag
- * @param {Function} [callback] Callback which will be run when the script is done
- * @param {boolean} [async=false] Whether to load modules asynchronously.
- * Ignored (and defaulted to `true`) if the document-ready event has already occurred.
+ * @param {string} module Name of the top-level module whose dependencies shall be
+ * 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.
+ * @param {Object} [unresolved] Hash used to track the current dependency
+ * chain; used to report loops in the dependency graph.
+ * @throws {Error} If any unregistered module or a dependency loop is encountered
*/
- function addScript( src, callback, async ) {
- // Using isReady directly instead of storing it locally from a $().ready callback (bug 31895)
- if ( $.isReady || async ) {
- $.ajax( {
- url: src,
- dataType: 'script',
- // Force jQuery behaviour to be for crossDomain. Otherwise jQuery would use
- // XHR for a same domain request instead of <script>, which changes the request
- // headers (potentially missing a cache hit), and reduces caching in general
- // since browsers cache XHR much less (if at all). And XHR means we retreive
- // text, so we'd need to $.globalEval, which then messes up line numbers.
- crossDomain: true,
- cache: true,
- async: true
- } ).always( callback );
- } else {
+ function sortDependencies( module, resolved, unresolved ) {
+ var n, deps, len, skip;
+
+ if ( !hasOwn.call( registry, module ) ) {
+ throw new Error( 'Unknown dependency: ' + module );
+ }
+
+ if ( registry[ module ].skip !== null ) {
/*jshint evil:true */
- document.write( mw.html.element( 'script', { 'src': src }, '' ) );
- if ( callback ) {
- // Document.write is synchronous, so this is called when it's done.
- // FIXME: That's a lie. doc.write isn't actually synchronous.
- callback();
+ skip = new Function( registry[ module ].skip );
+ registry[ module ].skip = null;
+ if ( skip() ) {
+ registry[ module ].skipped = true;
+ registry[ module ].dependencies = [];
+ registry[ module ].state = 'ready';
+ handlePending( module );
+ return;
+ }
+ }
+
+ // Resolves dynamic loader function and replaces it with its own results
+ if ( $.isFunction( registry[ module ].dependencies ) ) {
+ registry[ module ].dependencies = registry[ module ].dependencies();
+ // Ensures the module's dependencies are always in an array
+ if ( typeof registry[ module ].dependencies !== 'object' ) {
+ registry[ module ].dependencies = [ registry[ module ].dependencies ];
+ }
+ }
+ if ( $.inArray( module, resolved ) !== -1 ) {
+ // Module already resolved; nothing to do
+ return;
+ }
+ // Create unresolved if not passed in
+ if ( !unresolved ) {
+ unresolved = {};
+ }
+ // Tracks down dependencies
+ deps = registry[ module ].dependencies;
+ len = deps.length;
+ for ( n = 0; n < len; n += 1 ) {
+ if ( $.inArray( deps[ n ], resolved ) === -1 ) {
+ if ( unresolved[ deps[ n ] ] ) {
+ throw new Error(
+ 'Circular reference detected: ' + module +
+ ' -> ' + deps[ n ]
+ );
+ }
+
+ // Add to unresolved
+ unresolved[ module ] = true;
+ sortDependencies( deps[ n ], resolved, unresolved );
+ delete unresolved[ module ];
}
}
+ resolved[ resolved.length ] = module;
+ }
+
+ /**
+ * Get a list of module names that a module depends on in their proper dependency
+ * order.
+ *
+ * @private
+ * @param {string[]} module Array of string module names
+ * @return {Array} List of dependencies, including 'module'.
+ */
+ function resolve( modules ) {
+ var resolved = [];
+ $.each( modules, function ( idx, module ) {
+ sortDependencies( module, resolved );
+ } );
+ return resolved;
+ }
+
+ /**
+ * Load and execute a script with callback.
+ *
+ * @private
+ * @param {string} src URL to script, will be used as the src attribute in the script tag
+ * @return {jQuery.Promise}
+ */
+ function addScript( src ) {
+ return $.ajax( {
+ url: src,
+ dataType: 'script',
+ // Force jQuery behaviour to be for crossDomain. Otherwise jQuery would use
+ // XHR for a same domain request instead of <script>, which changes the request
+ // headers (potentially missing a cache hit), and reduces caching in general
+ // since browsers cache XHR much less (if at all). And XHR means we retreive
+ // text, so we'd need to $.globalEval, which then messes up line numbers.
+ crossDomain: true,
+ cache: true
+ } );
+ }
+
+ /**
+ * Utility function for execute()
+ *
+ * @ignore
+ */
+ function addLink( media, url ) {
+ var el = document.createElement( 'link' );
+ // Support: IE
+ // Insert in document *before* setting href
+ getMarker().before( el );
+ el.rel = 'stylesheet';
+ if ( media && media !== 'all' ) {
+ el.media = media;
+ }
+ // If you end up here from an IE exception "SCRIPT: Invalid property value.",
+ // see #addEmbeddedCSS, bug 31676, and bug 47277 for details.
+ el.href = url;
}
/**
@@ -1131,47 +1221,30 @@
* @param {string} module Module name to execute
*/
function execute( module ) {
- var key, value, media, i, urls, cssHandle, checkCssHandles,
+ var key, value, media, i, urls, cssHandle, checkCssHandles, runScript,
cssHandlesRegistered = false;
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 );
- } else if ( registry[module].state === 'loading' ) {
- throw new Error( 'Module has not completed loading yet: ' + module );
- } else if ( registry[module].state === 'ready' ) {
- throw new Error( 'Module has already been executed: ' + module );
}
-
- /**
- * Define loop-function here for efficiency
- * and to avoid re-using badly scoped variables.
- * @ignore
- */
- function addLink( media, url ) {
- var el = document.createElement( 'link' );
- // Support: IE
- // Insert in document *before* setting href
- getMarker().before( el );
- el.rel = 'stylesheet';
- if ( media && media !== 'all' ) {
- el.media = media;
- }
- // If you end up here from an IE exception "SCRIPT: Invalid property value.",
- // see #addEmbeddedCSS, bug 31676, and bug 47277 for details.
- el.href = url;
+ if ( registry[ module ].state !== 'loaded' ) {
+ throw new Error( 'Module in state "' + registry[ module ].state + '" may not be executed: ' + module );
}
- function runScript() {
- var script, markModuleReady, nestedAddScript;
+ registry[ module ].state = 'executing';
+
+ runScript = function () {
+ var script, markModuleReady, nestedAddScript, legacyWait,
+ // Expand to include dependencies since we have to exclude both legacy modules
+ // and their dependencies from the legacyWait (to prevent a circular dependency).
+ legacyModules = resolve( mw.config.get( 'wgResourceLoaderLegacyModules', [] ) );
try {
- script = registry[module].script;
+ script = registry[ module ].script;
markModuleReady = function () {
- registry[module].state = 'ready';
+ registry[ module ].state = 'ready';
handlePending( module );
};
- nestedAddScript = function ( arr, callback, async, i ) {
+ nestedAddScript = function ( arr, callback, i ) {
// Recursively call addScript() in its own callback
// for each element of arr.
if ( i >= arr.length ) {
@@ -1180,85 +1253,94 @@
return;
}
- addScript( arr[i], function () {
- nestedAddScript( arr, callback, async, i + 1 );
- }, async );
+ addScript( arr[ i ] ).always( function () {
+ nestedAddScript( arr, callback, i + 1 );
+ } );
};
- if ( $.isArray( script ) ) {
- nestedAddScript( script, markModuleReady, registry[module].async, 0 );
- } else if ( $.isFunction( script ) ) {
- registry[module].state = 'ready';
- // Pass jQuery twice so that the signature of the closure which wraps
- // the script can bind both '$' and 'jQuery'.
- script( $, $ );
- handlePending( module );
- }
+ legacyWait = ( $.inArray( module, legacyModules ) !== -1 )
+ ? $.Deferred().resolve()
+ : mw.loader.using( legacyModules );
+
+ legacyWait.always( function () {
+ if ( $.isArray( script ) ) {
+ nestedAddScript( script, markModuleReady, 0 );
+ } else if ( $.isFunction( script ) ) {
+ // Pass jQuery twice so that the signature of the closure which wraps
+ // the script can bind both '$' and 'jQuery'.
+ script( $, $ );
+ markModuleReady();
+ } else if ( typeof script === 'string' ) {
+ // Site and user modules are a legacy scripts that run in the global scope.
+ // This is transported as a string instead of a function to avoid needing
+ // to use string manipulation to undo the function wrapper.
+ if ( module === 'user' ) {
+ // Implicit dependency on the site module. Not real dependency because
+ // it should run after 'site' regardless of whether it succeeds or fails.
+ mw.loader.using( 'site' ).always( function () {
+ $.globalEval( script );
+ markModuleReady();
+ } );
+ } else {
+ $.globalEval( script );
+ markModuleReady();
+ }
+ } else {
+ // Module without script
+ markModuleReady();
+ }
+ } );
} 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
- registry[module].state = 'error';
+ registry[ module ].state = 'error';
mw.track( 'resourceloader.exception', { exception: e, module: module, source: 'module-execute' } );
handlePending( module );
}
- }
-
- // This used to be inside runScript, but since that is now fired asychronously
- // (after CSS is loaded) we need to set it here right away. It is crucial that
- // when execute() is called this is set synchronously, otherwise modules will get
- // executed multiple times as the registry will state that it isn't loading yet.
- registry[module].state = 'loading';
+ };
// Add localizations to message system
- if ( $.isPlainObject( registry[module].messages ) ) {
- mw.messages.set( registry[module].messages );
+ if ( registry[ module ].messages ) {
+ mw.messages.set( registry[ module ].messages );
}
// Initialise templates
- if ( registry[module].templates ) {
- mw.templates.set( module, registry[module].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.
- ( function () {
- var pending = 0;
- checkCssHandles = function () {
- // cssHandlesRegistered ensures we don't take off too soon, e.g. when
- // one of the cssHandles is fired while we're still creating more handles.
- if ( cssHandlesRegistered && pending === 0 && runScript ) {
- runScript();
- runScript = undefined; // Revoke
+ // Make sure we don't run the scripts until all stylesheet insertions have completed.
+ ( function () {
+ var pending = 0;
+ checkCssHandles = function () {
+ // cssHandlesRegistered ensures we don't take off too soon, e.g. when
+ // one of the cssHandles is fired while we're still creating more handles.
+ if ( cssHandlesRegistered && pending === 0 && runScript ) {
+ runScript();
+ runScript = undefined; // Revoke
+ }
+ };
+ cssHandle = function () {
+ var check = checkCssHandles;
+ pending++;
+ return function () {
+ if ( check ) {
+ pending--;
+ check();
+ check = undefined; // Revoke
}
};
- cssHandle = function () {
- var check = checkCssHandles;
- pending++;
- return function () {
- if ( check ) {
- pending--;
- check();
- check = undefined; // Revoke
- }
- };
- };
- }() );
- } else {
- // We are in blocking mode, and so we can't afford to wait for CSS
- cssHandle = function () {};
- // Run immediately
- checkCssHandles = runScript;
- }
+ };
+ }() );
// Process styles (see also mw.loader.implement)
// * back-compat: { <media>: css }
// * back-compat: { <media>: [url, ..] }
// * { "css": [css, ..] }
// * { "url": { <media>: [url, ..] } }
- if ( $.isPlainObject( registry[module].style ) ) {
- for ( key in registry[module].style ) {
- value = registry[module].style[key];
+ if ( registry[ module ].style ) {
+ for ( key in registry[ module ].style ) {
+ value = registry[ module ].style[ key ];
media = undefined;
if ( key !== 'url' && key !== 'css' ) {
@@ -1283,10 +1365,10 @@
for ( i = 0; i < value.length; i += 1 ) {
if ( key === 'bc-url' ) {
// back-compat: { <media>: [url, ..] }
- addLink( media, value[i] );
+ addLink( media, value[ i ] );
} else if ( key === 'css' ) {
// { "css": [css, ..] }
- addEmbeddedCSS( value[i], cssHandle() );
+ addEmbeddedCSS( value[ i ], cssHandle() );
}
}
// Not an array, but a regular object
@@ -1294,9 +1376,9 @@
} else if ( typeof value === 'object' ) {
// { "url": { <media>: [url, ..] } }
for ( media in value ) {
- urls = value[media];
+ urls = value[ media ];
for ( i = 0; i < urls.length; i += 1 ) {
- addLink( media, urls[i] );
+ addLink( media, urls[ i ] );
}
}
}
@@ -1316,34 +1398,39 @@
* @param {string|string[]} dependencies Module name or array of string module names
* @param {Function} [ready] Callback to execute when all dependencies are ready
* @param {Function} [error] Callback to execute when any dependency fails
- * @param {boolean} [async=false] Whether to load modules asynchronously.
- * Ignored (and defaulted to `true`) if the document-ready event has already occurred.
*/
- function request( dependencies, ready, error, async ) {
+ function request( dependencies, ready, error ) {
// Allow calling by single module name
if ( typeof dependencies === 'string' ) {
- dependencies = [dependencies];
+ dependencies = [ dependencies ];
}
// Add ready and error callbacks if they were given
if ( ready !== undefined || error !== undefined ) {
- jobs[jobs.length] = {
+ jobs.push( {
+ // Narrow down the list to modules that are worth waiting for
dependencies: $.grep( dependencies, function ( module ) {
var state = mw.loader.getState( module );
- return state === 'registered' || state === 'loaded' || state === 'loading';
+ return state === 'registered' || state === 'loaded' || state === 'loading' || state === 'executing';
} ),
ready: ready,
error: error
- };
+ } );
}
$.each( dependencies, function ( idx, module ) {
var state = mw.loader.getState( module );
+ // Only queue modules that are still in the initial 'registered' state
+ // (not ones already loading, ready or error).
if ( state === 'registered' && $.inArray( module, queue ) === -1 ) {
- queue.push( module );
- if ( async ) {
- registry[module].async = true;
+ // Private modules must be embedded in the page. Don't bother queuing
+ // these as the server will deny them anyway (T101806).
+ if ( registry[ module ].group === 'private' ) {
+ registry[ module ].state = 'error';
+ handlePending( module );
+ return;
}
+ queue.push( module );
}
} );
@@ -1362,7 +1449,7 @@
}
a.sort();
for ( key = 0; key < a.length; key += 1 ) {
- sorted[a[key]] = o[a[key]];
+ sorted[ a[ key ] ] = o[ a[ key ] ];
}
return sorted;
}
@@ -1370,6 +1457,7 @@
/**
* Converts a module map of the form { foo: [ 'bar', 'baz' ], bar: [ 'baz, 'quux' ] }
* to a query string of the form foo.bar,baz|bar.baz,quux
+ *
* @private
*/
function buildModulesString( moduleMap ) {
@@ -1378,31 +1466,26 @@
for ( prefix in moduleMap ) {
p = prefix === '' ? '' : prefix + '.';
- arr.push( p + moduleMap[prefix].join( ',' ) );
+ arr.push( p + moduleMap[ prefix ].join( ',' ) );
}
return arr.join( '|' );
}
/**
- * Asynchronously append a script tag to the end of the body
- * that invokes load.php
+ * Load modules from load.php
+ *
* @private
* @param {Object} moduleMap Module map, see #buildModulesString
* @param {Object} currReqBase Object with other parameters (other than 'modules') to use in the request
* @param {string} sourceLoadScript URL of load.php
- * @param {boolean} async Whether to load modules asynchronously.
- * Ignored (and defaulted to `true`) if the document-ready event has already occurred.
*/
- function doRequest( moduleMap, currReqBase, sourceLoadScript, async ) {
+ function doRequest( moduleMap, currReqBase, sourceLoadScript ) {
var request = $.extend(
{ modules: buildModulesString( moduleMap ) },
currReqBase
);
request = sortQuery( request );
- // 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 );
+ addScript( sourceLoadScript + '?' + $.param( request ) );
}
/**
@@ -1418,9 +1501,9 @@
*/
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;
+ if ( module[ 2 ] ) {
+ module[ 2 ] = $.map( module[ 2 ], function ( dep ) {
+ return typeof dep === 'number' ? modules[ dep ][ 0 ] : dep;
} );
}
} );
@@ -1449,9 +1532,9 @@
*/
work: function () {
var reqBase, splits, maxQueryLength, q, b, bSource, bGroup, bSourceGroup,
- source, concatSource, origBatch, group, g, i, modules, maxVersion, sourceLoadScript,
+ source, concatSource, origBatch, group, i, modules, sourceLoadScript,
currReqBase, currReqBaseLength, moduleMap, l,
- lastDotIndex, prefix, suffix, bytesAdded, async;
+ lastDotIndex, prefix, suffix, bytesAdded;
// Build a list of request parameters common to all requests.
reqBase = {
@@ -1466,12 +1549,12 @@
// 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 ( hasOwn.call( registry, queue[q] ) && 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];
+ if ( $.inArray( queue[ q ], batch ) === -1 ) {
+ batch[ batch.length ] = queue[ q ];
// Mark registered modules as loading
- registry[queue[q]].state = 'loading';
+ registry[ queue[ q ] ].state = 'loading';
}
}
}
@@ -1507,7 +1590,7 @@
// the error) instead of all of them.
mw.track( 'resourceloader.exception', { exception: err, source: 'store-eval' } );
origBatch = $.grep( origBatch, function ( module ) {
- return registry[module].state === 'loading';
+ return registry[ module ].state === 'loading';
} );
batch = batch.concat( origBatch );
}
@@ -1527,16 +1610,16 @@
// Split batch by source and by group.
for ( b = 0; b < batch.length; b += 1 ) {
- bSource = registry[batch[b]].source;
- bGroup = registry[batch[b]].group;
+ bSource = registry[ batch[ b ] ].source;
+ bGroup = registry[ batch[ b ] ].group;
if ( !hasOwn.call( splits, bSource ) ) {
- splits[bSource] = {};
+ splits[ bSource ] = {};
}
- if ( !hasOwn.call( splits[bSource], bGroup ) ) {
- splits[bSource][bGroup] = [];
+ if ( !hasOwn.call( splits[ bSource ], bGroup ) ) {
+ splits[ bSource ][ bGroup ] = [];
}
- bSourceGroup = splits[bSource][bGroup];
- bSourceGroup[bSourceGroup.length] = batch[b];
+ bSourceGroup = splits[ bSource ][ bGroup ];
+ bSourceGroup[ bSourceGroup.length ] = batch[ b ];
}
// Clear the batch - this MUST happen before we append any
@@ -1548,29 +1631,22 @@
for ( source in splits ) {
- sourceLoadScript = sources[source];
+ sourceLoadScript = sources[ source ];
- for ( group in splits[source] ) {
+ for ( group in splits[ source ] ) {
// Cache access to currently selected list of
// modules for this group from this source.
- modules = splits[source][group];
+ modules = splits[ source ][ group ];
- // Calculate the highest timestamp
- maxVersion = 0;
- for ( g = 0; g < modules.length; g += 1 ) {
- if ( registry[modules[g]].version > maxVersion ) {
- maxVersion = registry[modules[g]].version;
- }
- }
-
- currReqBase = $.extend( { version: formatVersionNumber( maxVersion ) }, reqBase );
+ currReqBase = $.extend( {
+ version: getCombinedVersion( modules )
+ }, reqBase );
// For user modules append a user name to the request.
if ( group === 'user' && mw.config.get( 'wgUserName' ) !== null ) {
currReqBase.user = mw.config.get( 'wgUserName' );
}
currReqBaseLength = $.param( currReqBase ).length;
- async = true;
// We may need to split up the request to honor the query string length limit,
// so build it piece by piece.
l = currReqBaseLength + 9; // '&modules='.length == 9
@@ -1579,42 +1655,35 @@
for ( i = 0; i < modules.length; i += 1 ) {
// Determine how many bytes this module would add to the query string
- lastDotIndex = modules[i].lastIndexOf( '.' );
+ lastDotIndex = modules[ i ].lastIndexOf( '.' );
// If lastDotIndex is -1, substr() returns an empty string
- prefix = modules[i].substr( 0, lastDotIndex );
- suffix = modules[i].slice( lastDotIndex + 1 );
+ prefix = modules[ i ].substr( 0, lastDotIndex );
+ suffix = modules[ i ].slice( lastDotIndex + 1 );
bytesAdded = hasOwn.call( moduleMap, prefix )
? suffix.length + 3 // '%2C'.length == 3
- : modules[i].length + 3; // '%7C'.length == 3
+ : modules[ i ].length + 3; // '%7C'.length == 3
// If the request would become too long, create a new one,
// but don't create empty requests
if ( maxQueryLength > 0 && !$.isEmptyObject( moduleMap ) && l + bytesAdded > maxQueryLength ) {
// This request would become too long, create a new one
// and fire off the old one
- doRequest( moduleMap, currReqBase, sourceLoadScript, async );
+ doRequest( moduleMap, currReqBase, sourceLoadScript );
moduleMap = {};
- async = true;
l = currReqBaseLength + 9;
mw.track( 'resourceloader.splitRequest', { maxQueryLength: maxQueryLength } );
}
if ( !hasOwn.call( moduleMap, prefix ) ) {
- moduleMap[prefix] = [];
- }
- moduleMap[prefix].push( suffix );
- if ( !registry[modules[i]].async ) {
- // If this module is blocking, make the entire request blocking
- // This is slightly suboptimal, but in practice mixing of blocking
- // and async modules will only occur in debug mode.
- async = false;
+ moduleMap[ prefix ] = [];
}
+ moduleMap[ prefix ].push( suffix );
l += bytesAdded;
}
// If there's anything left in moduleMap, request that too
if ( !$.isEmptyObject( moduleMap ) ) {
- doRequest( moduleMap, currReqBase, sourceLoadScript, async );
+ doRequest( moduleMap, currReqBase, sourceLoadScript );
}
}
}
@@ -1637,7 +1706,7 @@
// Allow multiple additions
if ( typeof id === 'object' ) {
for ( source in id ) {
- mw.loader.addSource( source, id[source] );
+ mw.loader.addSource( source, id[ source ] );
}
return true;
}
@@ -1650,14 +1719,15 @@
loadUrl = loadUrl.loadScript;
}
- sources[id] = loadUrl;
+ sources[ id ] = loadUrl;
return true;
},
/**
- * Register a module, letting the system know about it and its
- * properties. Startup modules contain calls to this function.
+ * Register a module, letting the system know about it and its properties.
+ *
+ * The startup modules contain calls to this method.
*
* When using multiple module registration by passing an array, dependencies that
* are specified as references to modules within the array will be resolved before
@@ -1665,7 +1735,8 @@
*
* @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|number} version Module version hash (falls backs to empty string)
+ * Can also be a number (timestamp) for compatibility with MediaWiki 1.25 and earlier.
* @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.
* @param {string} [group=null] Group which the module is in
@@ -1679,11 +1750,11 @@
resolveIndexedDependencies( module );
for ( i = 0, len = module.length; i < len; i++ ) {
// module is an array of module names
- if ( typeof module[i] === 'string' ) {
- mw.loader.register( module[i] );
+ if ( typeof module[ i ] === 'string' ) {
+ mw.loader.register( module[ i ] );
// module is an array of arrays
- } else if ( typeof module[i] === 'object' ) {
- mw.loader.register.apply( mw.loader, module[i] );
+ } else if ( typeof module[ i ] === 'object' ) {
+ mw.loader.register.apply( mw.loader, module[ i ] );
}
}
return;
@@ -1696,8 +1767,8 @@
throw new Error( 'module already registered: ' + module );
}
// List the module as registered
- registry[module] = {
- version: version !== undefined ? parseInt( version, 10 ) : 0,
+ registry[ module ] = {
+ version: version !== undefined ? String( version ) : '',
dependencies: [],
group: typeof group === 'string' ? group : null,
source: typeof source === 'string' ? source : 'local',
@@ -1706,11 +1777,11 @@
};
if ( typeof dependencies === 'string' ) {
// Allow dependencies to be given as a single module name
- registry[module].dependencies = [ dependencies ];
+ registry[ module ].dependencies = [ dependencies ];
} else if ( typeof dependencies === 'object' || $.isFunction( dependencies ) ) {
// Allow dependencies to be given as an array of module names
// or a function which returns an array
- registry[module].dependencies = dependencies;
+ registry[ module ].dependencies = dependencies;
}
},
@@ -1738,22 +1809,22 @@
* The reason css strings are not concatenated anymore is bug 31676. We now check
* whether it's safe to extend the stylesheet.
*
- * @param {Object} [msgs] List of key/value pairs to be added to mw#messages.
+ * @param {Object} [messages] 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, templates ) {
+ implement: function ( module, script, style, messages, templates ) {
// Validate input
if ( typeof module !== 'string' ) {
throw new Error( 'module must be of type string, not ' + typeof module );
}
- if ( script && !$.isFunction( script ) && !$.isArray( script ) ) {
- throw new Error( 'script must be of type function or array, not ' + typeof script );
+ if ( script && !$.isFunction( script ) && !$.isArray( script ) && typeof script !== 'string' ) {
+ throw new Error( 'script must be of type function, array, or script; not ' + typeof script );
}
if ( style && !$.isPlainObject( style ) ) {
throw new Error( 'style must be of type object, not ' + typeof style );
}
- if ( msgs && !$.isPlainObject( msgs ) ) {
- throw new Error( 'msgs must be of type object, not a ' + typeof msgs );
+ if ( messages && !$.isPlainObject( messages ) ) {
+ throw new Error( 'messages must be of type object, not a ' + typeof messages );
}
if ( templates && !$.isPlainObject( templates ) ) {
throw new Error( 'templates must be of type object, not a ' + typeof templates );
@@ -1763,18 +1834,18 @@
mw.loader.register( module );
}
// Check for duplicate implementation
- if ( hasOwn.call( registry, module ) && 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].templates = templates || {};
+ registry[ module ].script = script || null;
+ registry[ module ].style = style || null;
+ registry[ module ].messages = messages || null;
+ registry[ module ].templates = templates || null;
// The module may already have been marked as erroneous
- if ( $.inArray( registry[module].state, ['error', 'missing'] ) === -1 ) {
- registry[module].state = 'loaded';
- if ( allReady( registry[module].dependencies ) ) {
+ if ( $.inArray( registry[ module ].state, [ 'error', 'missing' ] ) === -1 ) {
+ registry[ module ].state = 'loaded';
+ if ( allReady( registry[ module ].dependencies ) ) {
execute( module );
}
}
@@ -1841,24 +1912,18 @@
* @param {string} [type='text/javascript'] MIME type to use if calling with a URL of an
* external script or style; acceptable values are "text/css" and
* "text/javascript"; if no type is provided, text/javascript is assumed.
- * @param {boolean} [async] Whether to load modules asynchronously.
- * Ignored (and defaulted to `true`) if the document-ready event has already occurred.
- * Defaults to `true` if loading a URL, `false` otherwise.
*/
- load: function ( modules, type, async ) {
+ load: function ( modules, type ) {
var filtered, l;
// Validate input
if ( typeof modules !== 'object' && typeof modules !== 'string' ) {
throw new Error( 'modules must be a string or an array, not a ' + typeof modules );
}
- // Allow calling with an external url or single dependency as a string
+ // Allow calling with a url or single dependency as a string
if ( typeof modules === 'string' ) {
- if ( /^(https?:)?\/\//.test( modules ) ) {
- if ( async === undefined ) {
- // Assume async for bug 34542
- async = true;
- }
+ // "https://example.org/x.js", "http://example.org/x.js", "//example.org/x.js", "/x.js"
+ if ( /^(https?:)?\/?\//.test( modules ) ) {
if ( type === 'text/css' ) {
// Support: IE 7-8
// Use properties instead of attributes as IE throws security
@@ -1871,7 +1936,7 @@
return;
}
if ( type === 'text/javascript' || type === undefined ) {
- addScript( modules, null, async );
+ addScript( modules );
return;
}
// Unknown type
@@ -1901,7 +1966,7 @@
return;
}
// Since some modules are not yet ready, queue up a request.
- request( filtered, undefined, undefined, async );
+ request( filtered, undefined, undefined );
},
/**
@@ -1915,21 +1980,21 @@
if ( typeof module === 'object' ) {
for ( m in module ) {
- mw.loader.state( m, module[m] );
+ mw.loader.state( m, module[ m ] );
}
return;
}
if ( !hasOwn.call( registry, module ) ) {
mw.loader.register( module );
}
- if ( $.inArray( state, ['ready', 'error', 'missing'] ) !== -1
- && registry[module].state !== state ) {
+ if ( $.inArray( state, [ 'ready', 'error', 'missing' ] ) !== -1
+ && registry[ module ].state !== state ) {
// Make sure pending modules depending on this one get executed if their
// dependencies are now fulfilled!
- registry[module].state = state;
+ registry[ module ].state = state;
handlePending( module );
} else {
- registry[module].state = state;
+ registry[ module ].state = state;
}
},
@@ -1941,10 +2006,10 @@
* in the registry.
*/
getVersion: function ( module ) {
- if ( !hasOwn.call( registry, module ) || registry[module].version === undefined ) {
+ if ( !hasOwn.call( registry, module ) || registry[ module ].version === undefined ) {
return null;
}
- return formatVersionNumber( registry[module].version );
+ return registry[ module ].version;
},
/**
@@ -1955,10 +2020,10 @@
* in the registry.
*/
getState: function ( module ) {
- if ( !hasOwn.call( registry, module ) || registry[module].state === undefined ) {
+ if ( !hasOwn.call( registry, module ) || registry[ module ].state === undefined ) {
return null;
}
- return registry[module].state;
+ return registry[ module ].state;
},
/**
@@ -1997,6 +2062,10 @@
// Whether the store is in use on this page.
enabled: null,
+ // Modules whose string representation exceeds 100 kB are ineligible
+ // for storage due to bug T66721.
+ MODULE_SIZE_MAX: 100000,
+
// The contents of the store, mapping '[module name]@[version]' keys
// to module implementations.
items: {},
@@ -2006,6 +2075,7 @@
/**
* Construct a JSON-serializable object representing the content of the store.
+ *
* @return {Object} Module store contents.
*/
toJSON: function () {
@@ -2024,6 +2094,7 @@
/**
* Get a key on which to vary the module cache.
+ *
* @return {string} String of concatenated vary conditions.
*/
getVary: function () {
@@ -2042,7 +2113,7 @@
*/
getModuleKey: function ( module ) {
return hasOwn.call( registry, module ) ?
- ( module + '@' + registry[module].version ) : null;
+ ( module + '@' + registry[ module ].version ) : null;
},
/**
@@ -2114,7 +2185,7 @@
key = mw.loader.store.getModuleKey( module );
if ( key in mw.loader.store.items ) {
mw.loader.store.stats.hits++;
- return mw.loader.store.items[key];
+ return mw.loader.store.items[ key ];
}
mw.loader.store.stats.misses++;
return false;
@@ -2127,7 +2198,7 @@
* @param {Object} descriptor The module's descriptor as set in the registry
*/
set: function ( module, descriptor ) {
- var args, key;
+ var args, key, src;
if ( !mw.loader.store.enabled ) {
return false;
@@ -2141,7 +2212,7 @@
// Module failed to load
descriptor.state !== 'ready' ||
// Unversioned, private, or site-/user-specific
- ( !descriptor.version || $.inArray( descriptor.group, [ 'private', 'user', 'site' ] ) !== -1 ) ||
+ ( !descriptor.version || $.inArray( descriptor.group, [ 'private', 'user' ] ) !== -1 ) ||
// Partial descriptor
$.inArray( undefined, [ descriptor.script, descriptor.style,
descriptor.messages, descriptor.templates ] ) !== -1
@@ -2162,8 +2233,8 @@
];
// 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];
+ if ( /^\s*\(/.test( args[ 1 ] ) ) {
+ args[ 1 ] = 'function' + args[ 1 ];
mw.track( 'resourceloader.assert', { source: 'bug-T59567' } );
}
} catch ( e ) {
@@ -2171,7 +2242,11 @@
return;
}
- mw.loader.store.items[key] = 'mw.loader.implement(' + args.join( ',' ) + ');';
+ src = 'mw.loader.implement(' + args.join( ',' ) + ');';
+ if ( src.length > mw.loader.store.MODULE_SIZE_MAX ) {
+ return false;
+ }
+ mw.loader.store.items[ key ] = src;
mw.loader.store.update();
},
@@ -2190,7 +2265,10 @@
module = key.slice( 0, key.indexOf( '@' ) );
if ( mw.loader.store.getModuleKey( module ) !== key ) {
mw.loader.store.stats.expired++;
- delete mw.loader.store.items[key];
+ delete mw.loader.store.items[ key ];
+ } else if ( mw.loader.store.items[ key ].length > mw.loader.store.MODULE_SIZE_MAX ) {
+ // This value predates the enforcement of a size limit on cached modules.
+ delete mw.loader.store.items[ key ];
}
}
},
@@ -2319,7 +2397,7 @@
var v, attrName, s = '<' + name;
for ( attrName in attrs ) {
- v = attrs[attrName];
+ v = attrs[ attrName ];
// Convert name=true, to name=name
if ( v === true ) {
v = attrName;
@@ -2366,6 +2444,7 @@
/**
* Wrapper object for raw HTML passed to mw.html.element().
+ *
* @class mw.html.Raw
*/
Raw: function ( value ) {
@@ -2374,6 +2453,7 @@
/**
* Wrapper object for CDATA element contents passed to mw.html.element()
+ *
* @class mw.html.Cdata
*/
Cdata: function ( value ) {
@@ -2388,6 +2468,9 @@
tokens: new Map()
},
+ // OOUI widgets specific to MediaWiki
+ widgets: {},
+
/**
* Registry and firing of events.
*
@@ -2440,12 +2523,13 @@
*/
return function ( name ) {
var list = hasOwn.call( lists, name ) ?
- lists[name] :
- lists[name] = $.Callbacks( 'memory' );
+ lists[ name ] :
+ lists[ name ] = $.Callbacks( 'memory' );
return {
/**
* Register a hook handler
+ *
* @param {Function...} handler Function to bind.
* @chainable
*/
@@ -2453,6 +2537,7 @@
/**
* Unregister a hook handler
+ *
* @param {Function...} handler Function to unbind.
* @chainable
*/
@@ -2460,6 +2545,7 @@
/**
* Run a hook.
+ *
* @param {Mixed...} data
* @chainable
*/
@@ -2514,10 +2600,33 @@
}
}
- // subscribe to error streams
+ // Subscribe to error streams
mw.trackSubscribe( 'resourceloader.exception', log );
mw.trackSubscribe( 'resourceloader.assert', log );
+ /**
+ * Fired when all modules associated with the page have finished loading.
+ *
+ * @event resourceloader_loadEnd
+ * @member mw.hook
+ */
+ $( function () {
+ var loading = $.grep( mw.loader.getModuleNames(), function ( module ) {
+ return mw.loader.getState( module ) === 'loading';
+ } );
+ // In order to use jQuery.when (which stops early if one of the promises got rejected)
+ // cast any loading failures into successes. We only need a callback, not the module.
+ loading = $.map( loading, function ( module ) {
+ return mw.loader.using( module ).then( null, function () {
+ return $.Deferred().resolve();
+ } );
+ } );
+ $.when.apply( $, loading ).then( function () {
+ mwPerformance.mark( 'mwLoadEnd' );
+ mw.hook( 'resourceloader.loadEnd' ).fire();
+ } );
+ } );
+
// Attach to window and globally alias
window.mw = window.mediaWiki = mw;
}( jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.log.js b/resources/src/mediawiki/mediawiki.log.js
index ad68967a..053fb1a1 100644
--- a/resources/src/mediawiki/mediawiki.log.js
+++ b/resources/src/mediawiki/mediawiki.log.js
@@ -79,6 +79,7 @@
// Restore original methods
mw.log.warn = original.warn;
+ mw.log.error = original.error;
mw.log.deprecate = original.deprecate;
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.notification.common.css b/resources/src/mediawiki/mediawiki.notification.common.css
new file mode 100644
index 00000000..a1309c29
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.notification.common.css
@@ -0,0 +1,7 @@
+.mw-notification-area {
+ position: absolute;
+}
+
+.mw-notification-area-floating {
+ position: fixed;
+}
diff --git a/resources/src/mediawiki/mediawiki.notification.css b/resources/src/mediawiki/mediawiki.notification.css
index ae399ce7..632ae821 100644
--- a/resources/src/mediawiki/mediawiki.notification.css
+++ b/resources/src/mediawiki/mediawiki.notification.css
@@ -1,5 +1,4 @@
.mw-notification-area {
- position: absolute;
top: 0;
right: 0;
padding: 1em 1em 0 0;
@@ -8,10 +7,6 @@
z-index: 10000;
}
-.mw-notification-area-floating {
- position: fixed;
-}
-
.mw-notification {
padding: 0.25em 1em;
margin-bottom: 0.5em;
@@ -25,3 +20,13 @@
.mw-notification-title {
font-weight: bold;
}
+
+.mw-notification-type-warn {
+ border-color: #F5BE00; /* yellow */
+ background-color: #FFFFE8;
+}
+
+.mw-notification-type-error {
+ border-color: #EB3941; /* red */
+ background-color: #FFF8F8;
+}
diff --git a/resources/src/mediawiki/mediawiki.notification.js b/resources/src/mediawiki/mediawiki.notification.js
index 132c334f..eeb7bb37 100644
--- a/resources/src/mediawiki/mediawiki.notification.js
+++ b/resources/src/mediawiki/mediawiki.notification.js
@@ -39,6 +39,12 @@
}
}
+ if ( options.type ) {
+ // Sanitize options.type
+ options.type = options.type.replace( /[ _\-]+/g, '-' ).replace( /[^\-a-z0-9]+/ig, '' );
+ $notification.addClass( 'mw-notification-type-' + options.type );
+ }
+
if ( options.title ) {
$notificationTitle = $( '<div class="mw-notification-title"></div>' )
.text( options.title )
@@ -356,7 +362,7 @@
$notifications.each( function () {
var notif = $( this ).data( 'mw.notification' );
if ( notif ) {
- notif[fn]();
+ notif[ fn ]();
}
} );
}
@@ -364,6 +370,7 @@
/**
* Initialisation.
* Must only be called once, and not before the document is ready.
+ *
* @ignore
*/
function init() {
@@ -386,12 +393,12 @@
// on links from hiding a notification.
.on( 'click', 'a', function ( e ) {
e.stopPropagation();
- } )
- .hide();
+ } );
// Prepend the notification area to the content area and save it's object.
mw.util.$content.prepend( $area );
offset = $area.offset();
+ $area.hide();
function updateAreaMode() {
var isFloating = $window.scrollTop() > offset.top;
@@ -414,6 +421,7 @@
/**
* Pause auto-hide timers for all notifications.
* Notifications will not auto-hide until resume is called.
+ *
* @see mw.Notification#pause
*/
pause: function () {
@@ -479,11 +487,16 @@
* - title:
* An optional title for the notification. Will be displayed above the
* content. Usually in bold.
+ *
+ * - type:
+ * An optional string for the type of the message used for styling:
+ * Examples: 'info', 'warn', 'error'.
*/
defaults: {
autoHide: true,
tag: false,
- title: undefined
+ title: undefined,
+ type: false
},
/**
diff --git a/resources/src/mediawiki/mediawiki.notify.js b/resources/src/mediawiki/mediawiki.notify.js
index c1e1dabf..0f3a0867 100644
--- a/resources/src/mediawiki/mediawiki.notify.js
+++ b/resources/src/mediawiki/mediawiki.notify.js
@@ -6,8 +6,9 @@
/**
* @see mw.notification#notify
- * @param message
- * @param options
+ * @see mw.notification#defaults
+ * @param {HTMLElement|HTMLElement[]|jQuery|mw.Message|string} message
+ * @param {Object} options See mw.notification#defaults for details.
* @return {jQuery.Promise}
*/
mw.notify = function ( message, options ) {
diff --git a/resources/src/mediawiki/mediawiki.searchSuggest.js b/resources/src/mediawiki/mediawiki.searchSuggest.js
index 7b7ccf3f..6c7484e2 100644
--- a/resources/src/mediawiki/mediawiki.searchSuggest.js
+++ b/resources/src/mediawiki/mediawiki.searchSuggest.js
@@ -2,8 +2,22 @@
* Add search suggestions to the search form.
*/
( function ( mw, $ ) {
+ mw.searchSuggest = {
+ request: function ( api, query, response, maxRows ) {
+ return api.get( {
+ action: 'opensearch',
+ search: query,
+ namespace: 0,
+ limit: maxRows,
+ suggest: ''
+ } ).done( function ( data ) {
+ response( data[ 1 ] );
+ } );
+ }
+ };
+
$( function () {
- var api, map, resultRenderCache, searchboxesSelectors,
+ var api, map, searchboxesSelectors,
// Region where the suggestions box will appear directly below
// (using the same width). Can be a container element or the input
// itself, depending on what suits best in the environment.
@@ -12,19 +26,20 @@
// element (not the search form, as that would leave the buttons
// vertically between the input and the suggestions).
$searchRegion = $( '#simpleSearch, #searchInput' ).first(),
- $searchInput = $( '#searchInput' );
+ $searchInput = $( '#searchInput' ),
+ previousSearchText = $searchInput.val();
// Compatibility map
map = {
// SimpleSearch is broken in Opera < 9.6
- opera: [['>=', 9.6]],
+ opera: [ [ '>=', 9.6 ] ],
// Older Konquerors are unable to position the suggestions correctly (bug 50805)
- konqueror: [['>=', '4.11']],
+ konqueror: [ [ '>=', '4.11' ] ],
docomo: false,
blackberry: false,
// Support for iOS 6 or higher. It has not been tested on iOS 5 or lower
- ipod: [['>=', 6]],
- iphone: [['>=', 6]]
+ ipod: [ [ '>=', 6 ] ],
+ iphone: [ [ '>=', 6 ] ]
};
if ( !$.client.test( map ) ) {
@@ -32,52 +47,101 @@
}
// Compute form data for search suggestions functionality.
- function computeResultRenderCache( context ) {
+ function getFormData( context ) {
var $form, baseHref, linkParams;
- // Compute common parameters for links' hrefs
- $form = context.config.$region.closest( 'form' );
+ if ( !context.formData ) {
+ // Compute common parameters for links' hrefs
+ $form = context.config.$region.closest( 'form' );
+
+ baseHref = $form.attr( 'action' );
+ baseHref += baseHref.indexOf( '?' ) > -1 ? '&' : '?';
+
+ linkParams = $form.serializeObject();
+
+ context.formData = {
+ textParam: context.data.$textbox.attr( 'name' ),
+ linkParams: linkParams,
+ baseHref: baseHref
+ };
+ }
+
+ return context.formData;
+ }
- baseHref = $form.attr( 'action' );
- baseHref += baseHref.indexOf( '?' ) > -1 ? '&' : '?';
+ /**
+ * Callback that's run when the user changes the search input text
+ * 'this' is the search input box (jQuery object)
+ *
+ * @ignore
+ */
+ function onBeforeUpdate() {
+ var searchText = this.val();
+
+ if ( searchText && searchText !== previousSearchText ) {
+ mw.track( 'mediawiki.searchSuggest', {
+ action: 'session-start'
+ } );
+ }
+ previousSearchText = searchText;
+ }
- linkParams = $form.serializeObject();
+ /**
+ * Callback that's run when suggestions have been updated either from the cache or the API
+ * 'this' is the search input box (jQuery object)
+ *
+ * @ignore
+ */
+ function onAfterUpdate() {
+ var context = this.data( 'suggestionsContext' );
- return {
- textParam: context.data.$textbox.attr( 'name' ),
- linkParams: linkParams,
- baseHref: baseHref
- };
+ mw.track( 'mediawiki.searchSuggest', {
+ action: 'impression-results',
+ numberOfResults: context.config.suggestions.length,
+ // FIXME: when other types of search become available change this value accordingly
+ // See the API call below (opensearch = prefix)
+ resultSetType: 'prefix'
+ } );
}
// The function used to render the suggestions.
function renderFunction( text, context ) {
- if ( !resultRenderCache ) {
- resultRenderCache = computeResultRenderCache( context );
- }
+ var formData = getFormData( context );
// linkParams object is modified and reused
- resultRenderCache.linkParams[ resultRenderCache.textParam ] = text;
+ formData.linkParams[ formData.textParam ] = text;
// this is the container <div>, jQueryfied
this.text( text )
.wrap(
$( '<a>' )
- .attr( 'href', resultRenderCache.baseHref + $.param( resultRenderCache.linkParams ) )
+ .attr( 'href', formData.baseHref + $.param( formData.linkParams ) )
.attr( 'title', text )
.addClass( 'mw-searchSuggest-link' )
);
}
- function specialRenderFunction( query, context ) {
- var $el = this;
+ // The function used when the user makes a selection
+ function selectFunction( $input ) {
+ var context = $input.data( 'suggestionsContext' ),
+ text = $input.val();
- if ( !resultRenderCache ) {
- resultRenderCache = computeResultRenderCache( context );
- }
+ mw.track( 'mediawiki.searchSuggest', {
+ action: 'click-result',
+ numberOfResults: context.config.suggestions.length,
+ clickIndex: context.config.suggestions.indexOf( text ) + 1
+ } );
+
+ // allow the form to be submitted
+ return true;
+ }
+
+ function specialRenderFunction( query, context ) {
+ var $el = this,
+ formData = getFormData( context );
// linkParams object is modified and reused
- resultRenderCache.linkParams[ resultRenderCache.textParam ] = query;
+ formData.linkParams[ formData.textParam ] = query;
if ( $el.children().length === 0 ) {
$el
@@ -96,11 +160,11 @@
}
if ( $el.parent().hasClass( 'mw-searchSuggest-link' ) ) {
- $el.parent().attr( 'href', resultRenderCache.baseHref + $.param( resultRenderCache.linkParams ) + '&fulltext=1' );
+ $el.parent().attr( 'href', formData.baseHref + $.param( formData.linkParams ) + '&fulltext=1' );
} else {
$el.wrap(
$( '<a>' )
- .attr( 'href', resultRenderCache.baseHref + $.param( resultRenderCache.linkParams ) + '&fulltext=1' )
+ .attr( 'href', formData.baseHref + $.param( formData.linkParams ) + '&fulltext=1' )
.addClass( 'mw-searchSuggest-link' )
);
}
@@ -120,22 +184,14 @@
$( searchboxesSelectors.join( ', ' ) )
.suggestions( {
fetch: function ( query, response, maxRows ) {
- var node = this[0];
+ var node = this[ 0 ];
api = api || new mw.Api();
- $.data( node, 'request', api.get( {
- action: 'opensearch',
- search: query,
- namespace: 0,
- limit: maxRows,
- suggest: ''
- } ).done( function ( data ) {
- response( data[ 1 ] );
- } ) );
+ $.data( node, 'request', mw.searchSuggest.request( api, query, response, maxRows ) );
},
cancel: function () {
- var node = this[0],
+ var node = this[ 0 ],
request = $.data( node, 'request' );
if ( request ) {
@@ -177,8 +233,16 @@
return;
}
- // Special suggestions functionality for skin-provided search box
+ // Special suggestions functionality and tracking for skin-provided search box
$searchInput.suggestions( {
+ update: {
+ before: onBeforeUpdate,
+ after: onAfterUpdate
+ },
+ result: {
+ render: renderFunction,
+ select: selectFunction
+ },
special: {
render: specialRenderFunction,
select: function ( $input ) {
@@ -190,8 +254,17 @@
$region: $searchRegion
} );
- // If the form includes any fallback fulltext search buttons, remove them
- $searchInput.closest( 'form' ).find( '.mw-fallbackSearchButton' ).remove();
+ $searchInput.closest( 'form' )
+ // track the form submit event
+ .on( 'submit', function () {
+ var context = $searchInput.data( 'suggestionsContext' );
+ mw.track( 'mediawiki.searchSuggest', {
+ action: 'submit-form',
+ numberOfResults: context.config.suggestions.length
+ } );
+ } )
+ // If the form includes any fallback fulltext search buttons, remove them
+ .find( '.mw-fallbackSearchButton' ).remove();
} );
}( mediaWiki, jQuery ) );
diff --git a/resources/src/mediawiki/mediawiki.startUp.js b/resources/src/mediawiki/mediawiki.startUp.js
deleted file mode 100644
index 028784c2..00000000
--- a/resources/src/mediawiki/mediawiki.startUp.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/*!
- * 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.storage.js b/resources/src/mediawiki/mediawiki.storage.js
new file mode 100644
index 00000000..39583926
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.storage.js
@@ -0,0 +1,58 @@
+( function ( mw ) {
+ 'use strict';
+
+ /**
+ * Library for storing device specific information. It should be used for storing simple
+ * strings and is not suitable for storing large chunks of data.
+ *
+ * @class mw.storage
+ * @singleton
+ */
+ mw.storage = {
+
+ localStorage: window.localStorage,
+
+ /**
+ * Retrieve value from device storage.
+ *
+ * @param {string} key Key of item to retrieve
+ * @return {string|boolean} False when localStorage not available, otherwise string
+ */
+ get: function ( key ) {
+ try {
+ return mw.storage.localStorage.getItem( key );
+ } catch ( e ) {}
+ return false;
+ },
+
+ /**
+ * Set a value in device storage.
+ *
+ * @param {string} key Key name to store under
+ * @param {string} value Value to be stored
+ * @returns {boolean} Whether the save succeeded or not
+ */
+ set: function ( key, value ) {
+ try {
+ mw.storage.localStorage.setItem( key, value );
+ return true;
+ } catch ( e ) {}
+ return false;
+ },
+
+ /**
+ * Remove a value from device storage.
+ *
+ * @param {string} key Key of item to remove
+ * @returns {boolean} Whether the save succeeded or not
+ */
+ remove: function ( key ) {
+ try {
+ mw.storage.localStorage.removeItem( key );
+ return true;
+ } catch ( e ) {}
+ return false;
+ }
+ };
+
+}( mediaWiki ) );
diff --git a/resources/src/mediawiki/mediawiki.template.js b/resources/src/mediawiki/mediawiki.template.js
index 61bbb0d7..c3db69e6 100644
--- a/resources/src/mediawiki/mediawiki.template.js
+++ b/resources/src/mediawiki/mediawiki.template.js
@@ -17,7 +17,7 @@
if ( !compiler.compile ) {
throw new Error( 'Compiler must implement compile method.' );
}
- compilers[name] = compiler;
+ compilers[ name ] = compiler;
},
/**
@@ -63,12 +63,12 @@
var compiledTemplate,
compilerName = this.getCompilerName( templateName );
- if ( !compiledTemplates[moduleName] ) {
- compiledTemplates[moduleName] = {};
+ if ( !compiledTemplates[ moduleName ] ) {
+ compiledTemplates[ moduleName ] = {};
}
compiledTemplate = this.compile( templateBody, compilerName );
- compiledTemplates[moduleName][ templateName ] = compiledTemplate;
+ compiledTemplates[ moduleName ][ templateName ] = compiledTemplate;
return compiledTemplate;
},
diff --git a/resources/src/mediawiki/mediawiki.template.mustache.js b/resources/src/mediawiki/mediawiki.template.mustache.js
index dcc3842b..624986a9 100644
--- a/resources/src/mediawiki/mediawiki.template.mustache.js
+++ b/resources/src/mediawiki/mediawiki.template.mustache.js
@@ -5,7 +5,7 @@
compile: function ( src ) {
return {
render: function ( data ) {
- return $.parseHTML( Mustache.render( src, data ) );
+ return $( $.parseHTML( Mustache.render( src, data ) ) );
}
};
}
diff --git a/resources/src/mediawiki/mediawiki.template.regexp.js b/resources/src/mediawiki/mediawiki.template.regexp.js
new file mode 100644
index 00000000..3ec0a1f5
--- /dev/null
+++ b/resources/src/mediawiki/mediawiki.template.regexp.js
@@ -0,0 +1,15 @@
+mediaWiki.template.registerCompiler( 'regexp', {
+ compile: function ( src ) {
+ return {
+ render: function () {
+ return new RegExp(
+ src
+ // Remove whitespace
+ .replace( /\s+/g, '' )
+ // Remove named capturing groups
+ .replace( /\?<\w+?>/g, '' )
+ );
+ }
+ };
+ }
+} );
diff --git a/resources/src/mediawiki/mediawiki.toc.js b/resources/src/mediawiki/mediawiki.toc.js
index 45338ea7..78627fca 100644
--- a/resources/src/mediawiki/mediawiki.toc.js
+++ b/resources/src/mediawiki/mediawiki.toc.js
@@ -15,25 +15,19 @@
$tocList.slideDown( 'fast' );
$tocToggleLink.text( mw.msg( 'hidetoc' ) );
$toc.removeClass( 'tochidden' );
- $.cookie( 'mw_hidetoc', null, {
- expires: 30,
- path: '/'
- } );
+ mw.cookie.set( 'hidetoc', null );
} else {
$tocList.slideUp( 'fast' );
$tocToggleLink.text( mw.msg( 'showtoc' ) );
$toc.addClass( 'tochidden' );
- $.cookie( 'mw_hidetoc', '1', {
- expires: 30,
- path: '/'
- } );
+ mw.cookie.set( 'hidetoc', '1' );
}
}
// Only add it if there is a complete TOC and it doesn't
// have a toggle added already
if ( $toc.length && $tocTitle.length && $tocList.length && !$tocToggleLink.length ) {
- hideToc = $.cookie( 'mw_hidetoc' ) === '1';
+ hideToc = mw.cookie.get( 'hidetoc' ) === '1';
$tocToggleLink = $( '<a href="#" id="togglelink"></a>' )
.text( hideToc ? mw.msg( 'showtoc' ) : mw.msg( 'hidetoc' ) )
diff --git a/resources/src/mediawiki/mediawiki.user.js b/resources/src/mediawiki/mediawiki.user.js
index 817c856c..b4baa66c 100644
--- a/resources/src/mediawiki/mediawiki.user.js
+++ b/resources/src/mediawiki/mediawiki.user.js
@@ -16,7 +16,7 @@
*/
function getUserInfo( info ) {
var api;
- if ( !deferreds[info] ) {
+ if ( !deferreds[ info ] ) {
deferreds.rights = $.Deferred();
deferreds.groups = $.Deferred();
@@ -38,13 +38,13 @@
}
- return deferreds[info].promise();
+ return deferreds[ info ].promise();
}
// 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 );
+ byteToHex[ i ] = ( i + 256 ).toString( 16 ).slice( 1 );
}
// mw.user with the properties options and tokens gets defined in mediawiki.js.
@@ -89,12 +89,12 @@
if ( ( i & 3 ) === 0 ) {
r = Math.random() * 0x100000000;
}
- rnds[i] = r >>> ( ( i & 3 ) << 3 ) & 255;
+ rnds[ i ] = r >>> ( ( i & 3 ) << 3 ) & 255;
}
}
// Convert from number to hex
for ( i = 0; i < 8; i++ ) {
- hexRnds[i] = byteToHex[rnds[i]];
+ hexRnds[ i ] = byteToHex[ rnds[ i ] ];
}
// Concatenation of two random integers with entrophy n and m
@@ -159,10 +159,10 @@
* @return {string} Random session ID
*/
sessionId: function () {
- var sessionId = $.cookie( 'mediaWiki.user.sessionId' );
- if ( sessionId === undefined || sessionId === null ) {
+ var sessionId = mw.cookie.get( 'mwuser-sessionId' );
+ if ( sessionId === null ) {
sessionId = mw.user.generateRandomSessionId();
- $.cookie( 'mediaWiki.user.sessionId', sessionId, { expires: null, path: '/' } );
+ mw.cookie.set( 'mwuser-sessionId', sessionId, { expires: null } );
}
return sessionId;
},
@@ -208,14 +208,14 @@
expires: 30
}, options || {} );
- cookie = $.cookie( 'mediaWiki.user.bucket:' + key );
+ cookie = mw.cookie.get( 'mwuser-bucket:' + key );
// Bucket information is stored as 2 integers, together as version:bucket like: "1:2"
if ( typeof cookie === 'string' && cookie.length > 2 && cookie.indexOf( ':' ) !== -1 ) {
parts = cookie.split( ':' );
- if ( parts.length > 1 && Number( parts[0] ) === options.version ) {
- version = Number( parts[0] );
- bucket = String( parts[1] );
+ if ( parts.length > 1 && Number( parts[ 0 ] ) === options.version ) {
+ version = Number( parts[ 0 ] );
+ bucket = String( parts[ 1 ] );
}
}
@@ -229,7 +229,7 @@
// Find range
range = 0;
for ( k in options.buckets ) {
- range += options.buckets[k];
+ range += options.buckets[ k ];
}
// Select random value within range
@@ -239,16 +239,16 @@
total = 0;
for ( k in options.buckets ) {
bucket = k;
- total += options.buckets[k];
+ total += options.buckets[ k ];
if ( total >= rand ) {
break;
}
}
- $.cookie(
- 'mediaWiki.user.bucket:' + key,
+ mw.cookie.set(
+ 'mwuser-bucket:' + key,
version + ':' + bucket,
- { path: '/', expires: Number( options.expires ) }
+ { expires: Number( options.expires ) * 86400 }
);
}
diff --git a/resources/src/mediawiki/mediawiki.userSuggest.js b/resources/src/mediawiki/mediawiki.userSuggest.js
index 3964f0b2..02a90fc3 100644
--- a/resources/src/mediawiki/mediawiki.userSuggest.js
+++ b/resources/src/mediawiki/mediawiki.userSuggest.js
@@ -6,7 +6,7 @@
config = {
fetch: function ( userInput, response, maxRows ) {
- var node = this[0];
+ var node = this[ 0 ];
api = api || new mw.Api();
@@ -15,7 +15,7 @@
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 ),
+ auprefix: userInput[ 0 ].toUpperCase() + userInput.slice( 1 ),
aulimit: maxRows
} ).done( function ( data ) {
var users = $.map( data.query.allusers, function ( userObj ) {
@@ -25,7 +25,7 @@
} ) );
},
cancel: function () {
- var node = this[0],
+ var node = this[ 0 ],
request = $.data( node, 'request' );
if ( request ) {
diff --git a/resources/src/mediawiki/mediawiki.util.js b/resources/src/mediawiki/mediawiki.util.js
index 6723e5f9..50fd0b42 100644
--- a/resources/src/mediawiki/mediawiki.util.js
+++ b/resources/src/mediawiki/mediawiki.util.js
@@ -33,7 +33,7 @@
];
for ( i = 0, l = selectors.length; i < l; i++ ) {
- $node = $( selectors[i] );
+ $node = $( selectors[ i ] );
if ( $node.length ) {
return $node.first();
}
@@ -82,6 +82,7 @@
.replace( /%29/g, ')' )
.replace( /%2C/g, ',' )
.replace( /%2F/g, '/' )
+ .replace( /%7E/g, '~' )
.replace( /%3A/g, ':' );
},
@@ -111,8 +112,8 @@
* For index.php use `mw.config.get( 'wgScript' )`.
*
* @since 1.18
- * @param str string Name of script (eg. 'api'), defaults to 'index'
- * @return string Address to script (eg. '/w/api.php' )
+ * @param {string} str Name of script (e.g. 'api'), defaults to 'index'
+ * @return {string} Address to script (e.g. '/w/api.php' )
*/
wikiScript: function ( str ) {
str = str || 'index';
@@ -159,12 +160,12 @@
url = location.href;
}
// Get last match, stop at hash
- var re = new RegExp( '^[^#]*[&?]' + $.escapeRE( param ) + '=([^&#]*)' ),
+ var re = new RegExp( '^[^#]*[&?]' + mw.RegExp.escape( param ) + '=([^&#]*)' ),
m = re.exec( url );
if ( m ) {
// Beware that decodeURIComponent is not required to understand '+'
// by spec, as encodeURIComponent does not produce it.
- return decodeURIComponent( m[1].replace( /\+/g, '%20' ) );
+ return decodeURIComponent( m[ 1 ].replace( /\+/g, '%20' ) );
}
return null;
},
@@ -298,7 +299,7 @@
// Error: Invalid nextnode
nextnode = undefined;
}
- if ( nextnode && ( nextnode.length !== 1 || nextnode[0].parentNode !== $ul[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;
@@ -317,7 +318,7 @@
// to get a localized access key label (bug 67946).
$link.updateTooltipAccessKeys();
- return $item[0];
+ return $item[ 0 ];
},
/**
diff --git a/resources/src/moment-local-dmy.js b/resources/src/moment-local-dmy.js
new file mode 100644
index 00000000..c67b93e9
--- /dev/null
+++ b/resources/src/moment-local-dmy.js
@@ -0,0 +1,16 @@
+// Use DMY date format for Moment.js, in accordance with MediaWiki's date formatting routines.
+// This affects English only (and languages without localisations, that fall back to English).
+// http://momentjs.com/docs/#/customization/long-date-formats/
+/*global moment */
+moment.locale( 'en', {
+ longDateFormat: {
+ // Unchanged, but have to be repeated here:
+ LT: 'h:mm A',
+ LTS: 'h:mm:ss A',
+ // Customized:
+ L: 'DD/MM/YYYY',
+ LL: 'D MMMM YYYY',
+ LLL: 'D MMMM YYYY LT',
+ LLLL: 'dddd, D MMMM YYYY LT'
+ }
+} );
diff --git a/resources/src/oojs-ui-local.css b/resources/src/oojs-ui-local.css
new file mode 100644
index 00000000..ab780fed
--- /dev/null
+++ b/resources/src/oojs-ui-local.css
@@ -0,0 +1,7 @@
+/* HACK: Set sane font-size for OOjs UI dialogs, in the most common case. This should be skin's
+ responsibility, but alas our skins tend to have the weirdest font-sizes on body. This shall be
+ removed when we make the MediaWiki skins bundled with tarball sane. (T91152) */
+body > .oo-ui-windowManager {
+ font-size: 12.8px;
+ font-size: 0.8rem;
+}
diff --git a/resources/src/polyfill-nodeTypes.js b/resources/src/polyfill-nodeTypes.js
new file mode 100644
index 00000000..556b51b4
--- /dev/null
+++ b/resources/src/polyfill-nodeTypes.js
@@ -0,0 +1,19 @@
+/**
+ * Adds window.Node with node types according to:
+ * http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1950641247
+ */
+
+window.Node = window.Node || {
+ ELEMENT_NODE: 1,
+ ATTRIBUTE_NODE: 2,
+ TEXT_NODE: 3,
+ CDATA_SECTION_NODE: 4,
+ ENTITY_REFERENCE_NODE: 5,
+ ENTITY_NODE: 6,
+ PROCESSING_INSTRUCTION_NODE: 7,
+ COMMENT_NODE: 8,
+ DOCUMENT_NODE: 9,
+ DOCUMENT_TYPE_NODE: 10,
+ DOCUMENT_FRAGMENT_NODE: 11,
+ NOTATION_NODE: 12
+};
diff --git a/resources/src/startup.js b/resources/src/startup.js
index a62cc9d6..1a10f837 100644
--- a/resources/src/startup.js
+++ b/resources/src/startup.js
@@ -3,8 +3,16 @@
* continue loading jQuery and the MediaWiki modules. This code should work on
* even the most ancient of browsers, so be very careful when editing.
*/
+/*jshint unused: false, evil: true */
+/*globals mw, RLQ: true, $VARS, $CODE, performance */
-var mediaWikiLoadStart = ( new Date() ).getTime();
+var mediaWikiLoadStart = ( new Date() ).getTime(),
+
+ mwPerformance = ( window.performance && performance.mark ) ? performance : {
+ mark: function () {}
+ };
+
+mwPerformance.mark( 'mwLoadStart' );
/**
* Returns false for Grade C supported browsers.
@@ -16,8 +24,6 @@ var mediaWikiLoadStart = ( new Date() ).getTime();
* - https://www.mediawiki.org/wiki/Compatibility#Browsers
* - https://jquery.com/browser-support/
*/
-
-/*jshint unused: false */
function isCompatible( ua ) {
if ( ua === undefined ) {
ua = navigator.userAgent;
@@ -26,18 +32,18 @@ function isCompatible( ua ) {
// Browsers with outdated or limited JavaScript engines get the no-JS experience
return !(
// Internet Explorer < 8
- ( ua.indexOf( 'MSIE' ) !== -1 && parseFloat( ua.split( 'MSIE' )[1] ) < 8 ) ||
+ ( ua.indexOf( 'MSIE' ) !== -1 && parseFloat( ua.split( 'MSIE' )[ 1 ] ) < 8 ) ||
// Firefox < 3
- ( ua.indexOf( 'Firefox/' ) !== -1 && parseFloat( ua.split( 'Firefox/' )[1] ) < 3 ) ||
+ ( ua.indexOf( 'Firefox/' ) !== -1 && parseFloat( ua.split( 'Firefox/' )[ 1 ] ) < 3 ) ||
// Opera < 12
( ua.indexOf( 'Opera/' ) !== -1 && ( ua.indexOf( 'Version/' ) === -1 ?
// "Opera/x.y"
- parseFloat( ua.split( 'Opera/' )[1] ) < 10 :
+ parseFloat( ua.split( 'Opera/' )[ 1 ] ) < 10 :
// "Opera/9.80 ... Version/x.y"
- parseFloat( ua.split( 'Version/' )[1] ) < 12
+ parseFloat( ua.split( 'Version/' )[ 1 ] ) < 12
) ) ||
// "Mozilla/0.0 ... Opera x.y"
- ( ua.indexOf( 'Opera ' ) !== -1 && parseFloat( ua.split( ' Opera ' )[1] ) < 10 ) ||
+ ( ua.indexOf( 'Opera ' ) !== -1 && parseFloat( ua.split( ' Opera ' )[ 1 ] ) < 10 ) ||
// BlackBerry < 6
ua.match( /BlackBerry[^\/]*\/[1-5]\./ ) ||
// Open WebOS < 1.5
@@ -52,11 +58,56 @@ function isCompatible( ua ) {
ua.match( /Opera Mini/ ) ||
// Nokia's Ovi Browser
ua.match( /S40OviBrowser/ ) ||
+ // MeeGo's browser
+ ua.match( /MeeGo/ ) ||
// Google Glass browser groks JS but UI is too limited
( ua.match( /Glass/ ) && ua.match( /Android/ ) )
);
}
-/**
- * The startUp() function will be auto-generated and added below.
- */
+// Conditional script injection
+( function () {
+ if ( !isCompatible() ) {
+ // Undo class swapping in case of an unsupported browser.
+ // See OutputPage::getHeadScripts().
+ document.documentElement.className = document.documentElement.className
+ .replace( /(^|\s)client-js(\s|$)/, '$1client-nojs$2' );
+ return;
+ }
+
+ /**
+ * The $CODE and $VARS placeholders are substituted in ResourceLoaderStartUpModule.php.
+ */
+ function startUp() {
+ mw.config = new mw.Map( $VARS.wgLegacyJavaScriptGlobals );
+
+ $CODE.registrations();
+
+ mw.config.set( $VARS.configuration );
+
+ // Must be after mw.config.set because these callbacks may use mw.loader which
+ // needs to have values 'skin', 'debug' etc. from mw.config.
+ window.RLQ = window.RLQ || [];
+ while ( RLQ.length ) {
+ RLQ.shift()();
+ }
+ window.RLQ = {
+ push: function ( fn ) {
+ fn();
+ }
+ };
+ }
+
+ var script = document.createElement( 'script' );
+ script.src = $VARS.baseModulesUri;
+ script.onload = script.onreadystatechange = function () {
+ if ( !script.readyState || /loaded|complete/.test( script.readyState ) ) {
+ // Clean up
+ script.onload = script.onreadystatechange = null;
+ script = null;
+ // Callback
+ startUp();
+ }
+ };
+ document.getElementsByTagName( 'head' )[ 0 ].appendChild( script );
+}() );